Hallo team,

it's my first post for this project, and the first one for an open source
project as well. Thus i kindly pleas to excuse my mistakes, should i have
done some.

I'm currently developing an web service framework for the Fiducia, germany
(huge Java banking project). My current task is to encrypt some parts of
the SOAP-Headers, containing attachments.

The structure of the SOAP-Message is like this:
---
<xml...>
<soapenv:Envelope>
   <soapenv:Header>
      <myNS:Header1>
      <!-- XML data-->
      </myNS:Header1>
      <myNS:Header2>
      <!-- XML data-->
      </myNS:Header2>
      ...
      <myNS:Attachments>
         <myNS:attachment>
            <!-- binary data base64 encoded -->
         </myNS:attachment>
         <myNS:attachment>
            <!-- binary data base64 encoded -->
         </myNS:attachment>
         <myNS:attachment>
            <!-- binary data base64 encoded -->
         </myNS:attachment>
         ...
      </myNS:Attachments>
      ...
      <myNS:HeaderX>
      <!-- XML data-->
      </myNS:HeaderX>
   </soapenv:Header>
   <soapenv:Body>
      <!-- XML data-->
   </soapenv:Body>
</soapenv:Envelope>
---

The attachments will be extracted later in their own MIME multipart parts,
using MTOM.
My problem is now, that i cannot encrypt the attachments separately from
each other. I can encrypt the whole Attachments-header using:
---
WSEncryptionPartencryptionPart = new WSEncryptionPart("Attachments", "
myNS-URI", "Content");
encryptionParts.add(encryptionPart);
---
But if I want to encrypt the attachment-elements separately using:
---
WSEncryptionPartencryptionPart = new WSEncryptionPart("attachment",
"myNS-URI", "Content");
encryptionParts.add(encryptionPart);
---
then only the firs one will be encrypted. The others will not.

I have quickly analysed the class
org.apache.ws.security.message.WSSecEncrypt, an found the code lines 495
and following, especially the one  with:
---
body = (Element) WSSecurityUtil.findElement(document, elemName, nmSpace);
---
Well, this line finds only one (the first one) element with the given name,
and not all of them. Then I implemented some work aound - not pretty, but
working - and now this class canencrypt all the elements with the given
name.
here is the modified method:
---
private Vector doEncryption(
        Document doc,
        SecretKey secretKey,
        KeyInfo keyInfo,
        Vector references
    ) throws WSSecurityException {

        XMLCipher xmlCipher = null;
        try {
            xmlCipher = XMLCipher.getInstance(symEncAlgo);
        } catch (XMLEncryptionException e3) {
            throw new WSSecurityException(
                WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, e3
            );
        }

        Vector encDataRef = new Vector();

        boolean cloneKeyInfo = false;
        for (int part = 0; part < references.size(); part++) {
            WSEncryptionPart encPart = (WSEncryptionPart) references.get
(part);

            String idToEnc = encPart.getId();
            String elemName = encPart.getName();
            String nmSpace = encPart.getNamespace();
            String modifier = encPart.getEncModifier();
            //
            // Third step: get the data to encrypt.
            //
            //Element body = null;
            if (idToEnc != null) {
                Element element =
                    WSSecurityUtil.findElementById(
                        document.getDocumentElement(), idToEnc,
WSConstants.WSU_NS
                    );
                if (element == null) {
                    element =
                        WSSecurityUtil.findElementById(document
.getDocumentElement(), idToEnc, null);
                }
                if (element == null) {
                    throw new WSSecurityException(
                        WSSecurityException.FAILURE,
                        "noEncElement",
                        new Object[] {"{" + nmSpace + "}" + elemName}
                    );
                }
                String encRef = encryptPart(document, encPart, element,
keyInfo, xmlCipher, secretKey);
                encDataRef.add(encRef);
            } else {
                NodeList elements = document.getElementsByTagNameNS
(nmSpace, elemName);
                if(elements == null || elements.getLength() <= 0) {
                    throw new WSSecurityException(
                            WSSecurityException.FAILURE,
                            "noEncElement",
                            new Object[] {"{" + nmSpace + "}" + elemName}
                        );
                }
                for(int i = 0; i < elements.getLength(); i++) {
                    Element element = (Element)elements.item(i);
                    String encRef = encryptPart(document, encPart, element,
keyInfo, xmlCipher, secretKey);
                    encDataRef.add(encRef);
                }
            }
        }
        return encDataRef;
    }
---

and here is the ne private method used by the modified one:
---
private String encryptPart(Document doc, WSEncryptionPart encPart, Element
element, KeyInfo keyInfo, XMLCipher xmlCipher, SecretKey secretKey ) throws
WSSecurityException
    {
        Vector encDataRef = new Vector();

        String modifier = encPart.getEncModifier();

        boolean content = modifier.equals("Content") ? true : false;
        String xencEncryptedDataId = wssConfig.getIdAllocator().createId(
"EncDataId-", element);
        encPart.setEncId(xencEncryptedDataId);

        boolean cloneKeyInfo = true;

        if (keyInfo == null) {
            keyInfo = new KeyInfo(document);
            SecurityTokenReference secToken = new SecurityTokenReference(
document);
            Reference ref = new Reference(document);
            if (encKeyIdDirectId) {
                ref.setURI(encKeyId);
            } else {
                ref.setURI("#" + encKeyId);
            }
            if (encKeyValueType != null) {
                ref.setValueType(encKeyValueType);
            }
            secToken.setReference(ref);
            keyInfo.addUnknownElement(secToken.getElement());
            Element keyInfoElement = keyInfo.getElement();
            keyInfoElement.setAttributeNS(
                WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX,
WSConstants.SIG_NS
            );
        }
        //
        // Fourth step: encrypt data, and set necessary attributes in
        // xenc:EncryptedData
        //
        try {
            if (modifier.equals("Header")) {

                Element elem =
                    doc.createElementNS(
                        WSConstants.WSSE11_NS, "wsse11:" + WSConstants.
ENCRYPTED_HEADER
                    );
                WSSecurityUtil.setNamespace(elem, WSConstants.WSSE11_NS,
WSConstants.WSSE11_PREFIX);
                String wsuPrefix =
                    WSSecurityUtil.setNamespace(elem, WSConstants.WSU_NS,
WSConstants.WSU_PREFIX);
                elem.setAttributeNS(
                    WSConstants.WSU_NS, wsuPrefix + ":Id",
                    wssConfig.getIdAllocator().createId("EncHeader-",
element)
                );

                NamedNodeMap map = element.getAttributes();

                for (int i = 0 ; i < map.getLength() ; i++) {
                    Attr attr = (Attr)map.item(i);
                    if (attr.getNamespaceURI().equals(WSConstants.
URI_SOAP11_ENV)
                        || attr.getNamespaceURI().equals(WSConstants.
URI_SOAP12_ENV)) {
                        String soapEnvPrefix =
                            WSSecurityUtil.setNamespace(
                                elem, attr.getNamespaceURI(), WSConstants.
DEFAULT_SOAP_PREFIX
                            );
                        elem.setAttributeNS(
                            attr.getNamespaceURI(),
                            soapEnvPrefix + ":" + attr.getLocalName(),
                            attr.getValue()
                        );
                    }
                }

                xmlCipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
                EncryptedData encData = xmlCipher.getEncryptedData();
                encData.setId(xencEncryptedDataId);
                encData.setKeyInfo(keyInfo);
                xmlCipher.doFinal(doc, element, content);

                Element encDataElem =
                    WSSecurityUtil.findElementById(
                        document.getDocumentElement(), xencEncryptedDataId,
null
                    );
                Node clone = encDataElem.cloneNode(true);
                elem.appendChild(clone);
                encDataElem.getParentNode().appendChild(elem);
                encDataElem.getParentNode().removeChild(encDataElem);
            } else {
                xmlCipher.init(XMLCipher.ENCRYPT_MODE, secretKey);
                EncryptedData encData = xmlCipher.getEncryptedData();
                encData.setId(xencEncryptedDataId);
                encData.setKeyInfo(keyInfo);
                xmlCipher.doFinal(doc, element, content);
            }
            if (cloneKeyInfo) {
                keyInfo = new KeyInfo((Element) keyInfo.getElement
().cloneNode(true), null);
            }
        } catch (Exception e2) {
            throw new WSSecurityException(
                WSSecurityException.FAILED_ENCRYPTION, null, null, e2
            );
        }
        return xencEncryptedDataId;

    }
---


I've just extraced the part of the old method responsible for the
encryption/marking of one Element and I call it for all found parts.
Perheadps you can discuss this modification and biuld it in one of the next
version - should it be approved.

And there is one more suggestion - the class "WSEncryptionPart"... Since
wss4j-1.5.8, or 1.5.9 you can set an XPath. But it is never used! The
lookup is done only by the namespaceURI and local name. Perheaps it will be
used in one of the future versions. But - what if the namespace/local name
does not correspond to the XPath? And if we have the XPath then we can use
only it, and forget the namespace/local name.
So it would be nice, if the class WSEncryptionPart would have all the
currently used constructors, and beside this  new one with the XPath.
 Something like this:
---
//old ones:
WSEncryptionPart(String id)
WSEncryptionPart(String id, String encMod)
WSEncryptionPart(String id, String encMod,int type)
WSEncryptionPart(String nm, String nmspace, String encMod)
WSEncryptionPart(String nm, String nmspace, String encMod, int type)

//new ones:
WSEncryptionPart(String xPath, String encMod)
WSEncryptionPart(String xPath, String encMod, int type)
---
and the newly added methods for setting and getting the xpath can be
deleted.
The search for the given element in the document can be then done by xpath
_or_ the old way, depending on the parameter set.



Greetings,

Marcin Markiewicz



----------------------------------------------------------------------------------------------------------------------------------------------


Fiducia IT AG
Fiduciastraße 20
76227 Karlsruhe

Sitz der Gesellschaft: Karlsruhe
AG Mannheim HRB 100059

Vorsitzender des Aufsichtsrats: Gregor Scheller
Vorsitzender des Vorstands: Michael Krings
Stellv. Vorsitzender des Vorstands: Klaus-Peter Bruns
Vorstand: Jens-Olaf Bartels, Hans-Peter Straberger

Umsatzsteuer-ID.Nr. DE143582320, http://www.fiducia.de
----------------------------------------------------------------------------------------------------------------------------------------------

Reply via email to