Goddag Marcin another way of accomplishing the objective is to refactor WSEncryptionPart to be an abstract class and force the concrete classes extending WSEncryptionPart to implement XPath in constructors,accessors and mutators
In order for this to pass muster you'll need to build testcases which calls these new methods to work for single element input as well as XMLPath extracted groups what criteria are you using to build the Vector for doEncryption? Vielen Danke, Martin ______________________________________________ Verzicht und Vertraulichkeitanmerkung/Note de déni et de confidentialité Diese Nachricht ist vertraulich. Sollten Sie nicht der vorgesehene Empfaenger sein, so bitten wir hoeflich um eine Mitteilung. Jede unbefugte Weiterleitung oder Fertigung einer Kopie ist unzulaessig. Diese Nachricht dient lediglich dem Austausch von Informationen und entfaltet keine rechtliche Bindungswirkung. Aufgrund der leichten Manipulierbarkeit von E-Mails koennen wir keine Haftung fuer den Inhalt uebernehmen. Ce message est confidentiel et peut être privilégié. Si vous n'êtes pas le destinataire prévu, nous te demandons avec bonté que pour satisfaire informez l'expéditeur. N'importe quelle diffusion non autorisée ou la copie de ceci est interdite. Ce message sert à l'information seulement et n'aura pas n'importe quel effet légalement obligatoire. Étant donné que les email peuvent facilement être sujets à la manipulation, nous ne pouvons accepter aucune responsabilité pour le contenu fourni. Subject: possible bug in the class "WSSecEncrypt" To: [email protected] CC: [email protected] From: [email protected] Date: Wed, 24 Nov 2010 13:39:42 +0100 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 ----------------------------------------------------------------------------------------------------------------------------------------------
