Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/EncryptedDataProcessor.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/EncryptedDataProcessor.java?rev=1540772&r1=1540771&r2=1540772&view=diff ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/EncryptedDataProcessor.java (original) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/EncryptedDataProcessor.java Mon Nov 11 16:54:52 2013 @@ -30,7 +30,6 @@ import javax.crypto.SecretKey; import javax.xml.namespace.QName; import org.w3c.dom.Element; -import org.w3c.dom.Node; import org.apache.wss4j.common.bsp.BSPRule; import org.apache.wss4j.common.crypto.AlgorithmSuite; import org.apache.wss4j.common.crypto.AlgorithmSuiteValidator; @@ -47,8 +46,6 @@ import org.apache.wss4j.dom.handler.Requ import org.apache.wss4j.dom.str.STRParser; import org.apache.wss4j.dom.str.SecurityTokenRefSTRParser; import org.apache.wss4j.dom.util.WSSecurityUtil; -import org.apache.xml.security.encryption.XMLCipher; -import org.apache.xml.security.encryption.XMLEncryptionException; /** * This will process incoming <code>xenc:EncryptedData</code> elements. @@ -68,7 +65,28 @@ public class EncryptedDataProcessor impl if (log.isDebugEnabled()) { log.debug("Found EncryptedData element"); } - Element kiElem = + + final String encryptedDataId = elem.getAttributeNS(null, "Id"); + + if (encryptedDataId != null) { + List<WSSecurityEngineResult> decryptionResults = wsDocInfo.getResultsByTag(WSConstants.ENCR); + for (int i = 0; i < decryptionResults.size(); i++) { + WSSecurityEngineResult wsSecurityEngineResult = decryptionResults.get(i); + @SuppressWarnings("unchecked") + List<WSDataRef> dataRefUris = (List<WSDataRef>)wsSecurityEngineResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS); + if (dataRefUris == null) { + continue; + } + for (int j = 0; j < dataRefUris.size(); j++) { + WSDataRef wsDataRef = dataRefUris.get(j); + if (encryptedDataId.equals(wsDataRef.getWsuId())) { + return new ArrayList<WSSecurityEngineResult>(); + } + } + } + } + + Element kiElem = WSSecurityUtil.getDirectChildElement(elem, "KeyInfo", WSConstants.SIG_NS); // KeyInfo cannot be null if (kiElem == null) { @@ -108,6 +126,7 @@ public class EncryptedDataProcessor impl byte[] secretKey = strParser.getSecretKey(); principal = strParser.getPrincipal(); key = KeyUtils.prepareSecretKey(symEncAlgo, secretKey); + encrKeyResults = new ArrayList<WSSecurityEngineResult>(); } else if (encryptedKeyElement != null) { EncryptedKeyProcessor encrKeyProc = new EncryptedKeyProcessor(); encrKeyResults = encrKeyProc.handleToken(encryptedKeyElement, request, wsDocInfo); @@ -137,76 +156,37 @@ public class EncryptedDataProcessor impl algorithmSuiteValidator.checkSymmetricKeyLength(key.getEncoded().length); algorithmSuiteValidator.checkSymmetricEncryptionAlgorithm(symEncAlgo); } - - // initialize Cipher .... - XMLCipher xmlCipher = null; - try { - xmlCipher = XMLCipher.getInstance(symEncAlgo); - xmlCipher.setSecureValidation(true); - xmlCipher.init(XMLCipher.DECRYPT_MODE, key); - } catch (XMLEncryptionException ex) { - throw new WSSecurityException( - WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, ex - ); - } - Node previousSibling = elem.getPreviousSibling(); - Node parent = elem.getParentNode(); - try { - xmlCipher.doFinal(elem.getOwnerDocument(), elem, false); - } catch (Exception e) { - throw new WSSecurityException( - WSSecurityException.ErrorCode.FAILED_CHECK, e - ); - } - - WSDataRef dataRef = new WSDataRef(); - dataRef.setWsuId(elem.getAttributeNS(null, "Id")); - dataRef.setAlgorithm(symEncAlgo); - dataRef.setContent(false); - - Node decryptedNode; - if (previousSibling == null) { - decryptedNode = parent.getFirstChild(); - } else { - decryptedNode = previousSibling.getNextSibling(); - } - if (decryptedNode != null && Node.ELEMENT_NODE == decryptedNode.getNodeType()) { - dataRef.setProtectedElement((Element)decryptedNode); - } - dataRef.setXpath(ReferenceListProcessor.getXPath(decryptedNode)); - - WSSecurityEngineResult result = + + WSDataRef dataRef = ReferenceListProcessor.decryptEncryptedData( + elem.getOwnerDocument(), encryptedDataId, elem, key, symEncAlgo, request); + + WSSecurityEngineResult result = new WSSecurityEngineResult(WSConstants.ENCR, Collections.singletonList(dataRef)); - result.put(WSSecurityEngineResult.TAG_ID, elem.getAttributeNS(null, "Id")); + result.put(WSSecurityEngineResult.TAG_ID, encryptedDataId); wsDocInfo.addResult(result); wsDocInfo.addTokenElement(elem); List<WSSecurityEngineResult> completeResults = new ArrayList<WSSecurityEngineResult>(); - if (encrKeyResults != null) { - completeResults.addAll(encrKeyResults); - } + completeResults.addAll(encrKeyResults); completeResults.add(result); WSSConfig wssConfig = request.getWssConfig(); if (wssConfig != null) { // Get hold of the plain text element - Element decryptedElem; - if (previousSibling == null) { - decryptedElem = (Element)parent.getFirstChild(); - } else { - decryptedElem = (Element)previousSibling.getNextSibling(); - } - QName el = new QName(decryptedElem.getNamespaceURI(), decryptedElem.getLocalName()); - Processor proc = request.getWssConfig().getProcessor(el); - if (proc != null) { - if (log.isDebugEnabled()) { - log.debug("Processing decrypted element with: " + proc.getClass().getName()); + Element decryptedElem = dataRef.getProtectedElement(); + if (decryptedElem != null) { //is null if we processed an attachment + QName el = new QName(decryptedElem.getNamespaceURI(), decryptedElem.getLocalName()); + Processor proc = request.getWssConfig().getProcessor(el); + if (proc != null) { + if (log.isDebugEnabled()) { + log.debug("Processing decrypted element with: " + proc.getClass().getName()); + } + List<WSSecurityEngineResult> results = + proc.handleToken(decryptedElem, request, wsDocInfo); + completeResults.addAll(0, results); + return completeResults; } - List<WSSecurityEngineResult> results = - proc.handleToken(decryptedElem, request, wsDocInfo); - completeResults.addAll(0, results); - return completeResults; } } return completeResults; @@ -233,5 +213,4 @@ public class EncryptedDataProcessor impl bspEnforcer.handleBSPRule(BSPRule.R5620); } } - }
Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/EncryptedKeyProcessor.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/EncryptedKeyProcessor.java?rev=1540772&r1=1540771&r2=1540772&view=diff ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/EncryptedKeyProcessor.java (original) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/EncryptedKeyProcessor.java Mon Nov 11 16:54:52 2013 @@ -485,7 +485,7 @@ public class EncryptedKeyProcessor imple } return ReferenceListProcessor.decryptEncryptedData( - doc, dataRefURI, encryptedDataElement, symmetricKey, symEncAlgo + doc, dataRefURI, encryptedDataElement, symmetricKey, symEncAlgo, data ); } Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/ReferenceListProcessor.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/ReferenceListProcessor.java?rev=1540772&r1=1540771&r2=1540772&view=diff ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/ReferenceListProcessor.java (original) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/ReferenceListProcessor.java Mon Nov 11 16:54:52 2013 @@ -19,14 +19,27 @@ package org.apache.wss4j.dom.processor; +import java.io.IOException; +import java.io.InputStream; +import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; - +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.apache.wss4j.common.ext.Attachment; +import org.apache.wss4j.common.ext.AttachmentRequestCallback; +import org.apache.wss4j.common.ext.AttachmentResultCallback; +import org.apache.wss4j.common.util.AttachmentUtils; +import org.apache.xml.security.algorithms.JCEMapper; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -78,8 +91,6 @@ public class ReferenceListProcessor impl * * @param elem contains the <code>ReferenceList</code> to the encrypted * data elements - * @param cb the callback handler to get the key for a key name stored if - * <code>KeyInfo</code> inside the encrypted data elements */ private List<WSDataRef> handleReferenceList( Element elem, @@ -198,7 +209,7 @@ public class ReferenceListProcessor impl return decryptEncryptedData( - doc, dataRefURI, encryptedDataElement, symmetricKey, symEncAlgo + doc, dataRefURI, encryptedDataElement, symmetricKey, symEncAlgo, data ); } @@ -301,22 +312,99 @@ public class ReferenceListProcessor impl String dataRefURI, Element encData, SecretKey symmetricKey, - String symEncAlgo + String symEncAlgo, + RequestData requestData ) throws WSSecurityException { - XMLCipher xmlCipher = null; - try { - xmlCipher = XMLCipher.getInstance(symEncAlgo); - xmlCipher.setSecureValidation(true); - xmlCipher.init(XMLCipher.DECRYPT_MODE, symmetricKey); - } catch (XMLEncryptionException ex) { - throw new WSSecurityException( - WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, ex - ); - } WSDataRef dataRef = new WSDataRef(); dataRef.setWsuId(dataRefURI); dataRef.setAlgorithm(symEncAlgo); + + String typeStr = encData.getAttribute("Type"); + if (typeStr != null && + (WSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_CONTENT_ONLY.equals(typeStr) || + WSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_COMPLETE.equals(typeStr))) { + + try { + Element cipherData = WSSecurityUtil.getDirectChildElement(encData, "CipherData", WSConstants.ENC_NS); + if (cipherData == null) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK); + } + Element cipherReference = WSSecurityUtil.getDirectChildElement(cipherData, "CipherReference", WSConstants.ENC_NS); + if (cipherReference == null) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK); + } + String uri = cipherReference.getAttributeNS(null, "URI"); + if (uri == null || uri.length() < 5) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK); + } + if (!uri.startsWith("cid:")) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK); + } + + CallbackHandler attachmentCallbackHandler = requestData.getAttachmentCallbackHandler(); + if (attachmentCallbackHandler == null) { + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK); + } + + final String attachmentId = uri.substring(4); + + AttachmentRequestCallback attachmentRequestCallback = new AttachmentRequestCallback(); + attachmentRequestCallback.setAttachmentId(attachmentId); + + attachmentCallbackHandler.handle(new Callback[]{attachmentRequestCallback}); + List<Attachment> attachments = attachmentRequestCallback.getAttachments(); + if (attachments == null || attachments.isEmpty() || !attachmentId.equals(attachments.get(0).getId())) { + throw new WSSecurityException( + WSSecurityException.ErrorCode.INVALID_SECURITY, + "empty", "Attachment not found" + ); + } + Attachment attachment = attachments.get(0); + + final String encAlgo = X509Util.getEncAlgo(encData); + final String jceAlgorithm = + JCEMapper.translateURItoJCEID(encAlgo); + final Cipher cipher = Cipher.getInstance(jceAlgorithm); + + InputStream attachmentInputStream = + AttachmentUtils.setupAttachmentDecryptionStream( + encAlgo, cipher, symmetricKey, attachment.getSourceStream()); + + Attachment resultAttachment = new Attachment(); + resultAttachment.setId(attachment.getId()); + resultAttachment.setMimeType(encData.getAttributeNS(null, "MimeType")); + resultAttachment.setSourceStream(attachmentInputStream); + resultAttachment.addHeaders(attachment.getHeaders()); + + if (WSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_COMPLETE.equals(typeStr)) { + AttachmentUtils.readAndReplaceEncryptedAttachmentHeaders( + resultAttachment.getHeaders(), attachmentInputStream); + } + + AttachmentResultCallback attachmentResultCallback = new AttachmentResultCallback(); + attachmentResultCallback.setAttachment(resultAttachment); + attachmentResultCallback.setAttachmentId(resultAttachment.getId()); + attachmentCallbackHandler.handle(new Callback[]{attachmentResultCallback}); + + } catch (UnsupportedCallbackException e) { + throw new WSSecurityException( + WSSecurityException.ErrorCode.FAILED_CHECK, e); + } catch (IOException e) { + throw new WSSecurityException( + WSSecurityException.ErrorCode.FAILED_CHECK, e); + } catch (NoSuchAlgorithmException e) { + throw new WSSecurityException( + WSSecurityException.ErrorCode.FAILED_CHECK, e); + } catch (NoSuchPaddingException e) { + throw new WSSecurityException( + WSSecurityException.ErrorCode.FAILED_CHECK, e); + } + + dataRef.setContent(true); + return dataRef; + } + boolean content = X509Util.isContent(encData); dataRef.setContent(content); @@ -326,6 +414,17 @@ public class ReferenceListProcessor impl encData = (Element) encData.getParentNode(); parent = encData.getParentNode(); } + + XMLCipher xmlCipher = null; + try { + xmlCipher = XMLCipher.getInstance(symEncAlgo); + xmlCipher.setSecureValidation(true); + xmlCipher.init(XMLCipher.DECRYPT_MODE, symmetricKey); + } catch (XMLEncryptionException ex) { + throw new WSSecurityException( + WSSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, ex + ); + } try { xmlCipher.doFinal(doc, encData, content); Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/SignatureProcessor.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/SignatureProcessor.java?rev=1540772&r1=1540771&r2=1540772&view=diff ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/SignatureProcessor.java (original) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/SignatureProcessor.java Mon Nov 11 16:54:52 2013 @@ -33,8 +33,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.xml.crypto.Data; import javax.xml.crypto.MarshalException; import javax.xml.crypto.NodeSetData; +import javax.xml.crypto.OctetStreamData; import javax.xml.crypto.XMLStructure; import javax.xml.crypto.dom.DOMStructure; import javax.xml.crypto.dsig.Manifest; @@ -52,11 +54,6 @@ import javax.xml.crypto.dsig.keyinfo.Key import javax.xml.crypto.dsig.spec.ExcC14NParameterSpec; import javax.xml.crypto.dsig.spec.HMACParameterSpec; -import org.apache.wss4j.common.principal.PublicKeyPrincipalImpl; -import org.apache.wss4j.common.principal.UsernameTokenPrincipal; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; import org.apache.wss4j.common.bsp.BSPRule; import org.apache.wss4j.common.cache.ReplayCache; import org.apache.wss4j.common.crypto.AlgorithmSuite; @@ -64,6 +61,8 @@ import org.apache.wss4j.common.crypto.Al import org.apache.wss4j.common.crypto.Crypto; import org.apache.wss4j.common.crypto.CryptoType; import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.common.principal.PublicKeyPrincipalImpl; +import org.apache.wss4j.common.principal.UsernameTokenPrincipal; import org.apache.wss4j.common.principal.WSDerivedKeyTokenPrincipal; import org.apache.wss4j.common.util.KeyUtils; import org.apache.wss4j.dom.WSConstants; @@ -80,12 +79,16 @@ import org.apache.wss4j.dom.message.toke import org.apache.wss4j.dom.str.STRParser; import org.apache.wss4j.dom.str.STRParser.REFERENCE_TYPE; import org.apache.wss4j.dom.str.SignatureSTRParser; +import org.apache.wss4j.dom.transform.AttachmentContentSignatureTransform; import org.apache.wss4j.dom.transform.STRTransform; import org.apache.wss4j.dom.transform.STRTransformUtil; import org.apache.wss4j.dom.util.WSSecurityUtil; import org.apache.wss4j.dom.util.XmlSchemaDateFormat; import org.apache.wss4j.dom.validate.Credential; import org.apache.wss4j.dom.validate.Validator; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; public class SignatureProcessor implements Processor { private static final org.slf4j.Logger LOG = @@ -357,10 +360,6 @@ public class SignatureProcessor implemen * </ul> * * @param elem the XMLSignature DOM Element. - * @param crypto the object that implements the access to the keystore and the - * handling of certificates. - * @param protectedRefs A list of (references) to the signed elements - * @param cb CallbackHandler instance to extract key passwords * @return the subject principal of the validated X509 certificate (the * authenticated subject). The calling function may use this * principal for further authentication or authorization. @@ -372,7 +371,7 @@ public class SignatureProcessor implemen PublicKey publicKey, byte[] secretKey, String signatureMethod, - RequestData data, + final RequestData data, WSDocInfo wsDocInfo ) throws WSSecurityException { if (LOG.isDebugEnabled()) { @@ -398,6 +397,9 @@ public class SignatureProcessor implemen context.setProperty("org.jcp.xml.dsig.secureValidation", Boolean.TRUE); context.setProperty(STRTransform.TRANSFORM_WS_DOC_INFO, wsDocInfo); + context.setProperty(AttachmentContentSignatureTransform.ATTACHMENT_CALLBACKHANDLER, + data.getAttachmentCallbackHandler()); + try { XMLSignature xmlSignature = signatureFactory.unmarshalXMLSignature(context); checkBSPCompliance(xmlSignature, data.getBSPEnforcer()); @@ -517,7 +519,6 @@ public class SignatureProcessor implemen * @param doc The owning document * @param signedInfo The SignedInfo object * @param requestData A RequestData instance - * @param protectedRefs A list of protected references * @return A list of protected references * @throws WSSecurityException */ @@ -537,10 +538,11 @@ public class SignatureProcessor implemen Element se = dereferenceSTR(doc, siRef, requestData, wsDocInfo); // If an STR Transform is not used then just find the cached element if (se == null) { - NodeSetData data = (NodeSetData)siRef.getDereferencedData(); - if (data != null) { + Data dereferencedData = siRef.getDereferencedData(); + if (dereferencedData instanceof NodeSetData) { + NodeSetData data = (NodeSetData)dereferencedData; java.util.Iterator<?> iter = data.iterator(); - + while (iter.hasNext()) { Node n = (Node)iter.next(); if (n instanceof Element) { @@ -548,6 +550,8 @@ public class SignatureProcessor implemen break; } } + } else if (dereferencedData instanceof OctetStreamData) { + se = doc.createElementNS("http://docs.oasis-open.org/wss/oasis-wss-SwAProfile-1.1", "attachment"); } } if (se == null) { Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/X509Util.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/X509Util.java?rev=1540772&r1=1540771&r2=1540772&view=diff ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/X509Util.java (original) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/X509Util.java Mon Nov 11 16:54:52 2013 @@ -50,7 +50,7 @@ public final class X509Util { return typeStr.equals(WSConstants.ENC_NS + "Content"); } } - return true; + return false; } public static String getEncAlgo(Node encBodyData) throws WSSecurityException { Added: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/resolvers/ResolverAttachment.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/resolvers/ResolverAttachment.java?rev=1540772&view=auto ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/resolvers/ResolverAttachment.java (added) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/resolvers/ResolverAttachment.java Mon Nov 11 16:54:52 2013 @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.wss4j.dom.resolvers; + +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; + +/* + * Fake Resolver for SwA (SOAP with Attachment) + */ +public class ResolverAttachment extends ResourceResolverSpi { + + private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + + @Override + public XMLSignatureInput engineResolveURI(ResourceResolverContext context) throws ResourceResolverException { + XMLSignatureInput xmlSignatureInput = new XMLSignatureInput(EMPTY_BYTE_ARRAY); + xmlSignatureInput.setSourceURI(context.uriToResolve); + return xmlSignatureInput; + } + + /* + * http://docs.oasis-open.org/wss-m/wss/v1.1.1/os/wss-SwAProfile-v1.1.1-os.html + * 5.2 Referencing Attachments + * For simplicity and interoperability this profile limits WS-Security references + * to attachments to CID scheme URLs. Attachments referenced from WS-Security signature + * references or cipher references MUST be referenced using CID scheme URLs. + */ + @Override + public boolean engineCanResolveURI(ResourceResolverContext context) { + if (context.uriToResolve == null) { + return false; + } + if (context.uriToResolve.startsWith("cid:")) { + return true; + } + return false; + } + + @Override + public boolean engineIsThreadSafe() { + return true; + } +} Added: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCiphertextTransform.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCiphertextTransform.java?rev=1540772&view=auto ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCiphertextTransform.java (added) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCiphertextTransform.java Mon Nov 11 16:54:52 2013 @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.wss4j.dom.transform; + +import org.apache.wss4j.dom.WSConstants; +import org.apache.xml.security.transforms.TransformSpi; + +/** + * Fake class to be able to create a Tranforms object + */ +public class AttachmentCiphertextTransform extends TransformSpi { + + @Override + protected String engineGetURI() { + return WSConstants.SWA_ATTACHMENT_CIPHERTEXT_TRANS; + } +} Added: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCompleteSignatureTransform.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCompleteSignatureTransform.java?rev=1540772&view=auto ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCompleteSignatureTransform.java (added) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCompleteSignatureTransform.java Mon Nov 11 16:54:52 2013 @@ -0,0 +1,99 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.wss4j.dom.transform; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.jcp.xml.dsig.internal.dom.ApacheOctetStreamData; +import org.apache.wss4j.common.ext.Attachment; +import org.apache.wss4j.common.util.AttachmentUtils; +import org.apache.wss4j.dom.WSConstants; + +import javax.xml.crypto.Data; +import javax.xml.crypto.OctetStreamData; +import javax.xml.crypto.XMLCryptoContext; +import javax.xml.crypto.dsig.TransformException; + +public class AttachmentCompleteSignatureTransform extends AttachmentContentSignatureTransform { + + public static final String TRANSFORM_URI = WSConstants.SWA_ATTACHMENT_COMPLETE_SIG_TRANS; + + @Override + public Data transform(Data data, XMLCryptoContext context) throws TransformException { + return transform(data, context, null); + } + + /* + * http://docs.oasis-open.org/wss-m/wss/v1.1.1/os/wss-SwAProfile-v1.1.1-os.html + * 5.2 Referencing Attachments + * This profile assumes, since it is not defined in RFC 2396 Section 4.2, that + * all cid: references are not same-document references and that therefore, under + * XMLDSIG, dereferencing a cid: URI always yields an octet stream as input to the + * transform chain [RFC2396], [XMLDSIG]. + */ + @Override + public Data transform(Data data, XMLCryptoContext context, OutputStream os) throws TransformException { + + String attachmentUri = ((ApacheOctetStreamData) data).getURI(); + String attachmentId = attachmentUri.substring(4); + + AttachmentTransformParameterSpec attachmentTransformParameterSpec = getAttachmentTransformParameterSpec(); + + Attachment attachment; + if (attachmentTransformParameterSpec != null) { + attachment = attachmentTransformParameterSpec.getAttachment(); + context.setProperty(ATTACHMENT_CALLBACKHANDLER, attachmentTransformParameterSpec.getAttachmentCallbackHandler()); + } else { + attachment = attachmentRequestCallback(context, attachmentId); + } + + try { + OutputStream outputStream = os; + if (outputStream == null) { + outputStream = new ByteArrayOutputStream(); + } + AttachmentUtils.canonizeMimeHeaders(os, attachment.getHeaders()); + processAttachment(context, os, attachmentUri, attachment); + + if (os == null) { + String mimeType = attachment.getMimeType(); + return new OctetStreamData( + new ByteArrayInputStream( + ((ByteArrayOutputStream)outputStream).toByteArray() + ), + attachmentUri, mimeType); + } + return null; + } catch (IOException e) { + throw new TransformException(e); + } + } + + @Override + public boolean isFeatureSupported(String feature) { + if (feature == null) { + throw new NullPointerException(); + } else { + return false; + } + } +} Added: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCompleteSignatureTransformProvider.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCompleteSignatureTransformProvider.java?rev=1540772&view=auto ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCompleteSignatureTransformProvider.java (added) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentCompleteSignatureTransformProvider.java Mon Nov 11 16:54:52 2013 @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.wss4j.dom.transform; + +import java.security.Provider; + +public class AttachmentCompleteSignatureTransformProvider extends Provider { + + private static final long serialVersionUID = -9148982936620100249L; + + public AttachmentCompleteSignatureTransformProvider() { + super("AttachmentCompleteSignatureTransform", 2.0, "Attachment Complete Signature Transform Provider"); + put( + "TransformService." + AttachmentCompleteSignatureTransform.TRANSFORM_URI, + "org.apache.wss4j.dom.transform.AttachmentCompleteSignatureTransform" + ); + put("TransformService." + AttachmentCompleteSignatureTransform.TRANSFORM_URI + " MechanismType", "DOM"); + } +} Added: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentContentSignatureTransform.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentContentSignatureTransform.java?rev=1540772&view=auto ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentContentSignatureTransform.java (added) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentContentSignatureTransform.java Mon Nov 11 16:54:52 2013 @@ -0,0 +1,248 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.wss4j.dom.transform; + +import org.apache.jcp.xml.dsig.internal.dom.ApacheOctetStreamData; +import org.apache.wss4j.common.ext.Attachment; +import org.apache.wss4j.common.ext.AttachmentRequestCallback; +import org.apache.wss4j.common.ext.AttachmentResultCallback; +import org.apache.wss4j.common.util.CRLFOutputStream; +import org.apache.wss4j.dom.WSConstants; +import org.apache.xml.security.c14n.CanonicalizationException; +import org.apache.xml.security.c14n.Canonicalizer; +import org.apache.xml.security.c14n.InvalidCanonicalizerException; +import org.apache.xml.security.signature.XMLSignatureInput; +import org.xml.sax.SAXException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.xml.crypto.Data; +import javax.xml.crypto.MarshalException; +import javax.xml.crypto.OctetStreamData; +import javax.xml.crypto.XMLCryptoContext; +import javax.xml.crypto.XMLStructure; +import javax.xml.crypto.dsig.TransformException; +import javax.xml.crypto.dsig.TransformService; +import javax.xml.crypto.dsig.spec.TransformParameterSpec; +import javax.xml.parsers.ParserConfigurationException; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.spec.AlgorithmParameterSpec; +import java.util.List; + +public class AttachmentContentSignatureTransform extends TransformService { + + public static final String TRANSFORM_URI = WSConstants.SWA_ATTACHMENT_CONTENT_SIG_TRANS; + public static final String ATTACHMENT_CALLBACKHANDLER = "AttachmentContentTransform.attachmentCallbackHandler"; + + private AttachmentTransformParameterSpec attachmentTransformParameterSpec; + + @Override + public void init(TransformParameterSpec params) throws InvalidAlgorithmParameterException { + if (!(params instanceof AttachmentTransformParameterSpec)) { + throw new InvalidAlgorithmParameterException("Expected AttachmentTransformParameterSpec"); + } + this.attachmentTransformParameterSpec = (AttachmentTransformParameterSpec) params; + } + + protected AttachmentTransformParameterSpec getAttachmentTransformParameterSpec() { + return attachmentTransformParameterSpec; + } + + @Override + public void init(XMLStructure parent, XMLCryptoContext context) throws InvalidAlgorithmParameterException { + } + + @Override + public void marshalParams(XMLStructure parent, XMLCryptoContext context) throws MarshalException { + } + + @Override + public AlgorithmParameterSpec getParameterSpec() { + return attachmentTransformParameterSpec; + } + + @Override + public Data transform(Data data, XMLCryptoContext context) throws TransformException { + return transform(data, context, null); + } + + /* + * http://docs.oasis-open.org/wss-m/wss/v1.1.1/os/wss-SwAProfile-v1.1.1-os.html + * 5.2 Referencing Attachments + * This profile assumes, since it is not defined in RFC 2396 Section 4.2, that + * all cid: references are not same-document references and that therefore, under + * XMLDSIG, dereferencing a cid: URI always yields an octet stream as input to the + * transform chain [RFC2396], [XMLDSIG]. + */ + @Override + public Data transform(Data data, XMLCryptoContext context, OutputStream os) throws TransformException { + + String attachmentUri = ((ApacheOctetStreamData) data).getURI(); + String attachmentId = attachmentUri.substring(4); + + Attachment attachment; + if (attachmentTransformParameterSpec != null) { + attachment = attachmentTransformParameterSpec.getAttachment(); + context.setProperty(ATTACHMENT_CALLBACKHANDLER, attachmentTransformParameterSpec.getAttachmentCallbackHandler()); + } else { + attachment = attachmentRequestCallback(context, attachmentId); + } + return processAttachment(context, os, attachmentUri, attachment); + } + + protected Attachment attachmentRequestCallback(XMLCryptoContext context, String attachmentId) throws TransformException { + CallbackHandler attachmentCallbackHandler = (CallbackHandler) context.getProperty(ATTACHMENT_CALLBACKHANDLER); + if (attachmentCallbackHandler == null) { + throw new TransformException("No attachment callbackhandler supplied"); + } + AttachmentRequestCallback attachmentRequestCallback = new AttachmentRequestCallback(); + attachmentRequestCallback.setAttachmentId(attachmentId); + try { + attachmentCallbackHandler.handle(new Callback[]{attachmentRequestCallback}); + } catch (Exception e) { + throw new TransformException(e); + } + List<Attachment> attachments = attachmentRequestCallback.getAttachments(); + if (attachments == null || attachments.isEmpty() || !attachmentId.equals(attachments.get(0).getId())) { + throw new TransformException("Attachment not found"); + } + return attachments.get(0); + } + + protected void attachmentResultCallback(XMLCryptoContext context, Attachment attachment) throws TransformException { + CallbackHandler attachmentCallbackHandler = (CallbackHandler) context.getProperty(ATTACHMENT_CALLBACKHANDLER); + if (attachmentCallbackHandler == null) { + throw new TransformException("No attachment callbackhandler supplied"); + } + AttachmentResultCallback attachmentResultCallback = new AttachmentResultCallback(); + attachmentResultCallback.setAttachmentId(attachment.getId()); + attachmentResultCallback.setAttachment(attachment); + try { + attachmentCallbackHandler.handle(new Callback[]{attachmentResultCallback}); + } catch (Exception e) { + throw new TransformException(e); + } + } + + @SuppressWarnings("resource") + protected Data processAttachment(XMLCryptoContext context, OutputStream os, String attachmentUri, Attachment attachment) throws TransformException { + try { + //try to reuse the inputStream in the hope that the provided inputStream is backed by a disk storage + InputStream inputStream = attachment.getSourceStream(); + if (!inputStream.markSupported()) { + inputStream = new BufferedInputStream(inputStream); + } + inputStream.mark(Integer.MAX_VALUE); //we can process at maximum 2G with the standard jdk streams + inputStream = new FilterInputStream(inputStream) { + @Override + public void close() throws IOException { + //I hate stuff which are closing _my_ streams! + } + }; + + OutputStream outputStream = os; + if (outputStream == null) { + outputStream = new ByteArrayOutputStream(); + } + + String mimeType = attachment.getMimeType(); + if ("text/xml".equalsIgnoreCase(mimeType) || + "application/xml".equals(mimeType) || + mimeType != null && mimeType.endsWith("+xml")) { //e.g. Application/mathml+xml + /* 5.4.2: + * Content of an XML Content-Type MUST be XML canonicalized using + * Exclusive XML Canonicalization without comments,as specified by + * the URI http://www.w3.org/2001/10/xml-exc-c14n# [Excl-Canon]. + * The reason for requiring Exclusive Canonicalization is that many + * implementations will support Exclusive Canonicalization for other + * XML Signature purposes, since this form of canonicalization + * supports context changes. The InclusiveNamespace PrefixList + * attribute SHOULD be empty or not present. + */ + Canonicalizer canon = Canonicalizer.getInstance(WSConstants.C14N_EXCL_OMIT_COMMENTS); + canon.setWriter(outputStream); + + XMLSignatureInput xmlSignatureInput = new XMLSignatureInput(inputStream); + canon.canonicalizeXPathNodeSet(xmlSignatureInput.getNodeSet()); + + } else if (mimeType != null && mimeType.startsWith("text/")) { + CRLFOutputStream crlfOutputStream = new CRLFOutputStream(outputStream); + int numBytes; + byte[] buf = new byte[8192]; + while ((numBytes = inputStream.read(buf)) != -1) { + crlfOutputStream.write(buf, 0, numBytes); + } + + } else { + int numBytes; + byte[] buf = new byte[8192]; + while ((numBytes = inputStream.read(buf)) != -1) { + outputStream.write(buf, 0, numBytes); + } + } + + //reset the inputStream to be able to reuse it + inputStream.reset(); + + //create a new attachment and do the result callback + final Attachment resultAttachment = new Attachment(); + resultAttachment.setId(attachment.getId()); + resultAttachment.setMimeType(mimeType); + resultAttachment.addHeaders(attachment.getHeaders()); + resultAttachment.setSourceStream(inputStream); + attachmentResultCallback(context, resultAttachment); + + if (os == null) { + return new OctetStreamData( + new ByteArrayInputStream( + ((ByteArrayOutputStream)outputStream).toByteArray() + ), + attachmentUri, mimeType); + } + return null; + } catch (IOException e) { + throw new TransformException(e); + } catch (InvalidCanonicalizerException e) { + throw new TransformException(e); + } catch (CanonicalizationException e) { + throw new TransformException(e); + } catch (ParserConfigurationException e) { + throw new TransformException(e); + } catch (SAXException e) { + throw new TransformException(e); + } + } + + @Override + public boolean isFeatureSupported(String feature) { + if (feature == null) { + throw new NullPointerException(); + } else { + return false; + } + } +} Added: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentContentSignatureTransformProvider.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentContentSignatureTransformProvider.java?rev=1540772&view=auto ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentContentSignatureTransformProvider.java (added) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentContentSignatureTransformProvider.java Mon Nov 11 16:54:52 2013 @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.wss4j.dom.transform; + +import java.security.Provider; + +public class AttachmentContentSignatureTransformProvider extends Provider { + + private static final long serialVersionUID = -9148982936620100249L; + + public AttachmentContentSignatureTransformProvider() { + super("AttachmentContentSignatureTransform", 2.0, "Attachment Content Signature Transform Provider"); + put( + "TransformService." + AttachmentContentSignatureTransform.TRANSFORM_URI, + "org.apache.wss4j.dom.transform.AttachmentContentSignatureTransform" + ); + put("TransformService." + AttachmentContentSignatureTransform.TRANSFORM_URI + " MechanismType", "DOM"); + } +} Added: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentTransformParameterSpec.java URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentTransformParameterSpec.java?rev=1540772&view=auto ============================================================================== --- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentTransformParameterSpec.java (added) +++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/transform/AttachmentTransformParameterSpec.java Mon Nov 11 16:54:52 2013 @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.wss4j.dom.transform; + +import org.apache.wss4j.common.ext.Attachment; + +import javax.security.auth.callback.CallbackHandler; +import javax.xml.crypto.dsig.spec.TransformParameterSpec; + +public class AttachmentTransformParameterSpec implements TransformParameterSpec { + + private CallbackHandler attachmentCallbackHandler; + private Attachment attachment; + + public AttachmentTransformParameterSpec( + CallbackHandler attachmentCallbackHandler, + Attachment attachment) { + this.attachmentCallbackHandler = attachmentCallbackHandler; + this.attachment = attachment; + } + + public CallbackHandler getAttachmentCallbackHandler() { + return attachmentCallbackHandler; + } + + public Attachment getAttachment() { + return attachment; + } +}
