Все восходит к тому, что CXF не работает с MTOM когда WSS включена :(
CXF Mailing List One
После борьбы немного больше с этой проблемой, это выглядит как один из способов разрешения которые могут быть в том числе распознаватель пользовательских ресурсов и преобразование
поэтому я добавил пользовательский распознаватель, так что WSS знать, где найти содержание вложений:.
package org.integration.client;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Collection;
import org.apache.cxf.message.Attachment;
import org.apache.log4j.Logger;
import org.apache.xml.security.signature.XMLSignatureInput;
import org.apache.xml.security.utils.resolver.ResourceResolverContext;
import org.apache.xml.security.utils.resolver.ResourceResolverException;
import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
public class AttachmentResolverSpi extends ResourceResolverSpi {
private static final String SUPPORTED_URI_PREFIX = "cid:urn";
private static final String ATTACHMENT_PREFIX = "cid:";
private static Logger logger = Logger.getLogger(AttachmentResolverSpi.class);
private Collection<Attachment> attachments;
@Override
public boolean engineIsThreadSafe() {
return false;
}
@Override
public boolean engineCanResolveURI(ResourceResolverContext context) {
if (context.uriToResolve == null) {
return false;
}
return context.uriToResolve.startsWith(SUPPORTED_URI_PREFIX);
}
@Override
public XMLSignatureInput engineResolveURI(ResourceResolverContext context)
throws ResourceResolverException {
String resourceId = getResourceId(context);
if (logger.isInfoEnabled()) {
logger.info("Looking up: " + resourceId);
}
Attachment attachment = getAttachment(resourceId);
if (attachment == null) {
logger.error("Unable to resolve attachment for " + resourceId);
throw new ResourceResolverException(context.uriToResolve, context.attr, context.baseUri);
}
if (logger.isInfoEnabled()) {
logger.info("Found attachment: " + attachment);
}
XMLSignatureInput result;
try {
result = new XMLSignatureInput(attachment.getDataHandler().getInputStream());
} catch (IOException e) {
logger.error("Unable to create xml signature input", e);
throw new ResourceResolverException(context.uriToResolve, context.attr, context.baseUri);
}
return result;
}
private String getResourceId(ResourceResolverContext context) {
String resourceId = context.uriToResolve;
try {
resourceId = URLDecoder.decode(resourceId, "UTF-8");
} catch (UnsupportedEncodingException e1) {
throw new RuntimeException("Unable to decode", e1);
}
if (resourceId.startsWith(ATTACHMENT_PREFIX)) {
resourceId = resourceId.substring(ATTACHMENT_PREFIX.length());
}
return resourceId;
}
private Attachment getAttachment(String resourceId) {
Collection<Attachment> attachments = getAttachments();
if (attachments == null) {
return null;
}
for(Attachment a : attachments) {
if (logger.isDebugEnabled()) {
logger.debug("Comparing " + a.getId() + " with " + resourceId);
}
if (a.getId().equals(resourceId)) {
return a;
}
}
return null;
}
protected Collection<Attachment> getAttachments() {
if (attachments == null) {
attachments = AttachmentCachingSaajInInterceptor.getAttachments();
}
return attachments;
}
}
Теперь дополнительный твик сказать CXF, как получить значение подписи для этого содержания:
package org.integration.client;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.apache.xml.security.exceptions.Base64DecodingException;
import org.apache.xml.security.signature.XMLSignatureInput;
import org.apache.xml.security.transforms.Transform;
import org.apache.xml.security.transforms.TransformSpi;
import org.apache.xml.security.transforms.TransformationException;
import org.xml.sax.SAXException;
public class TransformAttachmentCiphertext extends TransformSpi {
public static final String TRANSFORM_ATTACHMENT_CIPHERTEXT =
"http://docs.oasis-open.org/wss/oasis-wss-SwAProfile-1.1#Attachment-Ciphertext-Transform";
/**
* @see org.apache.xml.security.transforms.TransformSpi#engineGetURI()
*/
@Override
public String engineGetURI() {
return TRANSFORM_ATTACHMENT_CIPHERTEXT;
}
/**
* @see org.apache.xml.security.transforms.TransformSpi#enginePerformTransform(org.apache.xml.security.signature.XMLSignatureInput,
* java.io.OutputStream, org.apache.xml.security.transforms.Transform)
*/
@Override
protected XMLSignatureInput enginePerformTransform(XMLSignatureInput input,
OutputStream os, Transform transformObject) throws IOException,
CanonicalizationException, InvalidCanonicalizerException,
TransformationException, ParserConfigurationException, SAXException {
if (input.isOctetStream() || input.isNodeSet()) {
if (os == null) {
byte[] contentBytes = input.getBytes();
XMLSignatureInput output = new XMLSignatureInput(contentBytes);
return output;
}
if (input.isByteArray() || input.isNodeSet()) {
os.write(input.getBytes());
} else {
try {
org.apache.xml.security.utils.Base64.decode(new BufferedInputStream(input.getOctetStreamReal()), os);
} catch (Base64DecodingException e) {
throw new IOException("Unable to decode real octet stream", e);
}
}
XMLSignatureInput output = new XMLSignatureInput(new byte[] {});
output.setOutputStream(os);
return output;
}
return input;
}
}
Наконец, эти два элемента должны быть зарегистрированы с CXF:
import org.apache.xml.security.utils.resolver.ResourceResolver;
...
ResourceResolver.register(AttachmentResolverSpi.class, true);
org.apache.xml.security.transforms.Transform.register(TransformAttachmentCiphertext.TRANSFORM_ATTACHMENT_CIPHERTEXT, TransformAttachmentCiphertext.class);
Пожалуйста, не спросите меня, но CXF начинает дешифровать сообщения SOAP с помощью вложений после этих манипуляций. Но это не полное решение, поскольку оно по-прежнему не работает с вложениями MTOM. Что происходит, так это то, что CXF пытается обновить модель DOM с помощью содержимого вложения. Этот подход не работает по двум причинам. Сначала двоичные вложения обычно не образуют хорошо сформированные XML-элементы. Во-вторых, экземпляры приложения в сообщении SOAP не обновляются. Чтобы исправить это и, наконец, создать рабочее решение, мне пришлось взломать DocumentSerializer (разрешает проблему 1 с помощью base64, кодируя содержимое, если он не может быть разобран) и XMLCipher (разрешает проблему 2, заменяя экземпляры Attachment).
Предполагаю, что другим вариантом будет написать пользовательский ResourceResolver, а затем каким-то образом предоставить вложения через этот класс. Похож на перебор ... –
Каковы правила безопасности XML в такой ситуации? Я пробовал читать их один раз (много лет назад), но они были очень сонными ... –
А, мне жаль, что я не знал. Это очень странная настройка. Нам нужно настроить пользовательские заголовки, добавить токен двоичной безопасности, токен имени пользователя и отметку времени, а затем подписать все. Ответ возвращается и зашифрован. CXF отлично справляется с большинством вызовов, за исключением того, что с приложениями MTOM ... –