/** * 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.stax.impl.transformer; import org.apache.wss4j.common.ext.Attachment; import org.apache.wss4j.common.util.CRLFOutputStream; import org.apache.xml.security.exceptions.XMLSecurityException; import org.apache.xml.security.stax.ext.XMLSecurityConstants; import org.apache.xml.security.stax.ext.stax.XMLSecEvent; import org.apache.xml.security.stax.impl.transformer.TransformIdentity; import org.apache.xml.security.stax.impl.transformer.canonicalizer.Canonicalizer20010315_ExclOmitCommentsTransformer; import javax.xml.stream.XMLStreamException; import java.io.InputStream; import java.util.Map; public class AttachmentContentSignatureTransform extends TransformIdentity { public static final String ATTACHMENT = "attachment"; private Attachment attachment; @Override public XMLSecurityConstants.TransformMethod getPreferredTransformMethod(XMLSecurityConstants.TransformMethod forInput) { switch (forInput) { case XMLSecEvent: return XMLSecurityConstants.TransformMethod.InputStream; case InputStream: return XMLSecurityConstants.TransformMethod.InputStream; default: throw new IllegalArgumentException("Unsupported class " + forInput.name()); } } @Override public void setProperties(Map<String, Object> properties) throws XMLSecurityException { this.attachment = (Attachment) properties.get(ATTACHMENT); } protected Attachment getAttachment() { return attachment; } /* * 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 void transform(XMLSecEvent xmlSecEvent) throws XMLStreamException { throw new UnsupportedOperationException("transform(XMLSecEvent) not allowed"); } @Override public void transform(InputStream inputStream) throws XMLStreamException { String mimeType = getAttachment().getMimeType(); if (mimeType != null && (mimeType.matches("(?i)(text/xml).*") || mimeType.matches("(?i)(application/xml).*") || mimeType.matches("(?i)(application|image)/.*\\+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. */ Canonicalizer20010315_ExclOmitCommentsTransformer canon = new Canonicalizer20010315_ExclOmitCommentsTransformer(); try { canon.setOutputStream(getOutputStream()); } catch (XMLSecurityException e) { throw new XMLStreamException(e); } canon.transform(inputStream); } else if (mimeType != null && mimeType.matches("(?i)(text/).*")) { CRLFOutputStream crlfOutputStream = new CRLFOutputStream(getOutputStream()); try { setOutputStream(crlfOutputStream); } catch (XMLSecurityException e) { throw new XMLStreamException(e); } super.transform(inputStream); } else { super.transform(inputStream); } } }