package org.jentrata.ebms.as4.internal.routes;
import org.apache.camel.Exchange;
import org.apache.camel.LoggingLevel;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.wss4j.common.crypto.Crypto;
import org.apache.wss4j.common.ext.Attachment;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.dom.WSEncryptionPart;
import org.apache.wss4j.dom.WSSecurityEngine;
import org.apache.wss4j.dom.WSSecurityEngineResult;
import org.apache.wss4j.dom.handler.RequestData;
import org.apache.wss4j.dom.message.WSSecHeader;
import org.apache.wss4j.dom.message.WSSecSignature;
import org.apache.wss4j.dom.message.WSSecUsernameToken;
import org.jentrata.ebms.EbmsConstants;
import org.jentrata.ebms.MessageType;
import org.jentrata.ebms.cpa.PartnerAgreement;
import org.jentrata.ebms.cpa.pmode.PayloadService;
import org.jentrata.ebms.cpa.pmode.Security;
import org.jentrata.ebms.cpa.pmode.Signature;
import org.jentrata.ebms.cpa.pmode.SignaturePart;
import org.jentrata.ebms.cpa.pmode.UsernameToken;
import org.jentrata.ebms.internal.messaging.AttachmentCallbackHandler;
import org.jentrata.ebms.internal.security.UsernameTokenCallbackHandler;
import org.w3c.dom.Document;
import javax.activation.DataHandler;
import javax.security.auth.callback.CallbackHandler;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Provides WSSE integration for the incoming AS4 Message
*
* @author aaronwalker
*/
@SuppressWarnings("unchecked")
public class WSSERouteBuilder extends RouteBuilder {
private String wsseSecurityCheck = "direct:wsseSecurityCheck";
private String wsseAddSecurityToHeader = "direct:wsseAddSecurityToHeader";
private Crypto crypto;
@Override
public void configure() throws Exception {
final WSSecurityEngine securityEngine = new WSSecurityEngine();
from(wsseSecurityCheck)
.onException(WSSecurityException.class)
.setHeader(EbmsConstants.SECURITY_CHECK,constant(Boolean.FALSE))
.end()
.log(LoggingLevel.INFO, "Performing WSSE check for ${headers.JentrataCPAId} - on message:${headers.JentrataMessageID}")
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
PartnerAgreement agreement = exchange.getIn().getHeader(EbmsConstants.CPA, PartnerAgreement.class);
MessageType messageType = exchange.getIn().getHeader(EbmsConstants.MESSAGE_TYPE,MessageType.class);
if (agreement.hasResponderSecurityToken() || agreement.requiresSignature(messageType)) {
Document signedDoc = exchange.getIn().getBody(Document.class);
RequestData requestData = new RequestData();
requestData.setWssConfig(securityEngine.getWssConfig());
requestData.setSigVerCrypto(crypto);
requestData.setDecCrypto(crypto);
requestData.setDisableBSPEnforcement(agreement.getSecurity().isDisableBSPEnforcement());
if(agreement.hasResponderSecurityToken()) {
UsernameToken token = (UsernameToken) agreement.getResponder().getAuthorization();
requestData.getWssConfig().setPasswordsAreEncoded(token.isDigest());
requestData.setAddUsernameTokenCreated(token.isCreated());
requestData.setAddUsernameTokenNonce(token.isNonce());
requestData.setCallbackHandler(new UsernameTokenCallbackHandler(token));
}
AttachmentCallbackHandler attachmentCallback = null;
if(exchange.getIn().hasAttachments()) {
attachmentCallback = createAttachmentCallbackHandler(exchange);
requestData.setAttachmentCallbackHandler(attachmentCallback);
}
List<WSSecurityEngineResult> results;
try {
results = securityEngine.processSecurityHeader(signedDoc, null, requestData);
if(results != null && results.size() > 0) {
exchange.getIn().setHeader(EbmsConstants.SECURITY_CHECK,results.get(0).get(WSSecurityEngineResult.TAG_VALIDATED_TOKEN));
if(exchange.getIn().hasAttachments() && attachmentCallback != null && attachmentCallback.hasCallback()) {
exchange.getIn().setAttachments(attachmentCallback.getVerifiedAttachments());
}
} else {
if((messageType == MessageType.SIGNAL_MESSAGE_WITH_USER_MESSAGE || messageType == MessageType.SIGNAL_MESSAGE)
&& agreement.getSecurity().getSendReceiptReplyPattern() == Security.ReplyPatternType.Response) {
exchange.getIn().setHeader(EbmsConstants.SECURITY_CHECK,Boolean.TRUE);
} else {
exchange.getIn().setHeader(EbmsConstants.SECURITY_CHECK,Boolean.FALSE);
}
}
} catch (WSSecurityException ex) {
exchange.getIn().setHeader(EbmsConstants.SECURITY_CHECK,Boolean.FALSE);
exchange.getIn().setHeader(EbmsConstants.SECURITY_RESULTS,ex);
}
} else {
exchange.getIn().setHeader(EbmsConstants.SECURITY_CHECK,Boolean.TRUE);
}
}
})
.routeId("_jentrataWSSESecurityCheck");
from(wsseAddSecurityToHeader)
.log(LoggingLevel.INFO, "Adding UsernameToken for ${headers.JentrataCPAId} - on message:${headers.JentrataMessageID}")
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
Document message = exchange.getIn().getBody(Document.class);
PartnerAgreement agreement = exchange.getIn().getHeader(EbmsConstants.CPA, PartnerAgreement.class);
MessageType messageType = exchange.getIn().getHeader(EbmsConstants.MESSAGE_TYPE, MessageType.class);
if (agreement.hasInitiatorSecurityToken()
&& agreement.getInitiator().getAuthorization() instanceof UsernameToken) {
if(agreement.getSecurity().getSendReceiptReplyPattern() == Security.ReplyPatternType.Callback
|| messageType == MessageType.USER_MESSAGE) {
UsernameToken token = (UsernameToken) agreement.getInitiator().getAuthorization();
WSSecUsernameToken builder = new WSSecUsernameToken();
builder.setPasswordsAreEncoded(token.isDigest());
builder.setUserInfo(token.getUsername(), token.getPassword());
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(message);
Document signedDoc = builder.build(message, secHeader);
exchange.getIn().setBody(signedDoc);
}
} else {
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(message);
WSSecUsernameToken builder = new WSSecUsernameToken();
builder.setPasswordsAreEncoded(false);
builder.setUserInfo("dummy","dummy");
Document signedDoc = builder.build(message, secHeader);
secHeader.removeSecurityHeader(signedDoc);
}
}
})
.log(LoggingLevel.INFO, "Signing for ${headers.JentrataCPAId} - on message:${headers.JentrataMessageID}")
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
Document message = exchange.getIn().getBody(Document.class);
PartnerAgreement agreement = exchange.getIn().getHeader(EbmsConstants.CPA, PartnerAgreement.class);
MessageType messageType = exchange.getIn().getHeader(EbmsConstants.MESSAGE_TYPE, MessageType.class);
if (agreement.requiresSignature(messageType)) {
Signature signatureAgreement = agreement.getSecurity().getSignature();
List<WSEncryptionPart> parts = new ArrayList<>();
if (messageType == MessageType.USER_MESSAGE) {
for (SignaturePart signaturePart : signatureAgreement.getSignatureParts()) {
WSEncryptionPart part;
if (signaturePart.getNamespace() != null) {
part = new WSEncryptionPart(signaturePart.getElementName(), signaturePart.getNamespace(), signaturePart.getEncryptMethod());
} else {
part = new WSEncryptionPart(signaturePart.getElementName(), signaturePart.getEncryptMethod());
}
parts.add(part);
}
} else {
parts.add(new WSEncryptionPart(Signature.SOAP_BODY_PART.getElementName(), Signature.SOAP_BODY_PART.getNamespace(), Signature.SOAP_BODY_PART.getEncryptMethod()));
parts.add(new WSEncryptionPart(Signature.EBMS3_MESSAGE_PART.getElementName(), Signature.EBMS3_MESSAGE_PART.getNamespace(), Signature.EBMS3_MESSAGE_PART.getEncryptMethod()));
}
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(message);
WSSecSignature signature = new WSSecSignature();
signature.setUserInfo(signatureAgreement.getKeyStoreAlias(), signatureAgreement.getKeyStorePass());
signature.setSignatureAlgorithm(signatureAgreement.getSignatureAlgorithm());
signature.setDigestAlgo(signatureAgreement.getSignatureHashFunction());
signature.setParts(parts);
signature.getWsConfig().setAddInclusivePrefixes(agreement.getSecurity().isInclusiveNamespacesEnabled());
AttachmentCallbackHandler attachmentCallbackHandler = createAttachmentCallbackHandler(exchange);
signature.setAttachmentCallbackHandler(attachmentCallbackHandler);
Document signedDoc = signature.build(message, crypto, secHeader);
exchange.getIn().setBody(signedDoc);
exchange.getIn().setAttachments(attachmentCallbackHandler.getVerifiedAttachments());
}
}
})
.routeId("_jentrataWSSEInsertUsernameToken");
}
private AttachmentCallbackHandler createAttachmentCallbackHandler(Exchange exchange) throws IOException {
List<Attachment> attachments = new ArrayList<>();
if(exchange.getIn().hasAttachments()) {
Map<String,DataHandler> attachmentMap = exchange.getIn().getAttachments();
for(Map.Entry<String,DataHandler> entry : attachmentMap.entrySet()) {
Attachment attachment = new Attachment();
attachment.setId(entry.getKey());
attachment.setMimeType(entry.getValue().getContentType());
attachment.setSourceStream(entry.getValue().getInputStream());
attachments.add(attachment);
}
} else if(exchange.getIn().getHeader(EbmsConstants.MESSAGE_PAYLOADS) != null) {
List<Map<String, Object>> payloads = (List<Map<String, Object>>) exchange.getIn().getHeader(EbmsConstants.MESSAGE_PAYLOADS);
for(Map<String,Object> payload : payloads) {
Attachment attachment = new Attachment();
attachment.setId((String) payload.get("payloadId"));
String compressionType = (String) payload.get("compressionType");
if(compressionType == null || compressionType.isEmpty()) {
attachment.setMimeType((String) payload.get("contentType"));
} else {
attachment.setMimeType(compressionType);
}
byte [] content = (byte[]) payload.get("content");
attachment.setSourceStream(new ByteArrayInputStream(content));
attachments.add(attachment);
}
}
return new AttachmentCallbackHandler(attachments);
}
public String getWsseSecurityCheck() {
return wsseSecurityCheck;
}
public void setWsseSecurityCheck(String wsseSecurityCheck) {
this.wsseSecurityCheck = wsseSecurityCheck;
}
public String getWsseAddSecurityToHeader() {
return wsseAddSecurityToHeader;
}
public void setWsseAddSecurityToHeader(String wsseAddSecurityToHeader) {
this.wsseAddSecurityToHeader = wsseAddSecurityToHeader;
}
public Crypto getCrypto() {
return crypto;
}
public void setCrypto(Crypto crypto) {
this.crypto = crypto;
}
}