You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2011/08/24 18:46:56 UTC
svn commit: r1161199 - in
/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security:
saml/SamlEnvelopedInHandler.java saml/SamlEnvelopedOutInterceptor.java
xml/XmlSigInHandler.java xml/XmlSigOutInterceptor.java
Author: sergeyb
Date: Wed Aug 24 16:46:55 2011
New Revision: 1161199
URL: http://svn.apache.org/viewvc?rev=1161199&view=rev
Log:
[CXF-3587] Optionally signing content exclusive of SAML tokens
Modified:
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedInHandler.java
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.java
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigOutInterceptor.java
Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedInHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedInHandler.java?rev=1161199&r1=1161198&r2=1161199&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedInHandler.java (original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedInHandler.java Wed Aug 24 16:46:55 2011
@@ -27,9 +27,9 @@ import javax.xml.stream.XMLStreamReader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.message.Message;
@@ -91,16 +91,11 @@ public class SamlEnvelopedInHandler exte
}
private Element getActualBody(Element root) {
- NodeList list = root.getChildNodes();
- for (int i = 0; i < list.getLength(); i++) {
- Node node = list.item(i);
- if (node instanceof Element) {
- root.removeChild(node);
- return (Element)node;
- }
+ Element node = DOMUtils.getFirstElement(root);
+ if (node != null) {
+ root.removeChild(node);
}
- return null;
-
+ return node;
}
protected Element getNode(Element parent, String ns, String name) {
Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.java?rev=1161199&r1=1161198&r2=1161199&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.java (original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlEnvelopedOutInterceptor.java Wed Aug 24 16:46:55 2011
@@ -18,25 +18,26 @@
*/
package org.apache.cxf.rs.security.saml;
+import javax.xml.namespace.QName;
+
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-
import org.apache.cxf.helpers.DOMUtils;
+import org.apache.cxf.helpers.XMLUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.rs.security.xml.AbstractXmlSecOutInterceptor;
import org.apache.cxf.rs.security.xml.XmlEncOutInterceptor;
import org.apache.cxf.rs.security.xml.XmlSigOutInterceptor;
import org.apache.ws.security.saml.ext.AssertionWrapper;
+
public class SamlEnvelopedOutInterceptor extends AbstractXmlSecOutInterceptor {
- private static final String DEFAULT_ENV_NAME = "Envelope";
- private static final String DEFAULT_ENV_NAMESPACE = "http://org.apache.cxf/rs/env";
private static final String DEFAULT_ENV_PREFIX = "env";
- private String envelopeName = DEFAULT_ENV_NAME;
- private String envelopeNamespace = DEFAULT_ENV_NAMESPACE;
- private String envelopePrefix = DEFAULT_ENV_PREFIX;
+ private static final QName DEFAULT_ENV_QNAME =
+ new QName("http://org.apache.cxf/rs/env", "Envelope", DEFAULT_ENV_PREFIX);
+ private QName envelopeQName = DEFAULT_ENV_QNAME;
public SamlEnvelopedOutInterceptor() {
// SAML assertions may contain enveloped XML signatures so
@@ -56,15 +57,25 @@ public class SamlEnvelopedOutInterceptor
private Document createEnvelopedSamlToken(Message message, Document payloadDoc)
throws Exception {
+ Element docEl = payloadDoc.getDocumentElement();
+ AssertionWrapper assertion = SAMLUtils.createAssertion(message);
+
+ QName rootName = DOMUtils.getElementQName(payloadDoc.getDocumentElement());
+ if (rootName.equals(envelopeQName)) {
+ docEl.appendChild(assertion.toDOM(payloadDoc));
+ return payloadDoc;
+ }
+
Document newDoc = DOMUtils.createDocument();
+
Element root =
- newDoc.createElementNS(envelopeNamespace, envelopePrefix + ":" + envelopeName);
+ newDoc.createElementNS(envelopeQName.getNamespaceURI(),
+ envelopeQName.getPrefix() + ":" + envelopeQName.getLocalPart());
newDoc.appendChild(root);
- AssertionWrapper assertion = SAMLUtils.createAssertion(message);
+
Element assertionEl = assertion.toDOM(newDoc);
root.appendChild(assertionEl);
- Element docEl = payloadDoc.getDocumentElement();
payloadDoc.removeChild(docEl);
newDoc.adoptNode(docEl);
root.appendChild(docEl);
@@ -72,33 +83,15 @@ public class SamlEnvelopedOutInterceptor
}
- public void setEnvelopeName(String envelopeName) {
- this.envelopeName = envelopeName;
- }
-
-
- public String getEnvelopeName() {
- return envelopeName;
- }
-
-
- public void setEnvelopeNamespace(String envelopeNamespace) {
- this.envelopeNamespace = envelopeNamespace;
- }
-
-
- public String getEnvelopeNamespace() {
- return envelopeNamespace;
+ public void setEnvelopeName(String expandedName) {
+ setEnvelopeQName(XMLUtils.convertStringToQName(expandedName, DEFAULT_ENV_PREFIX));
}
-
-
- public void setEnvelopePrefix(String envelopePrefix) {
- this.envelopePrefix = envelopePrefix;
- }
-
-
- public String getEnvelopePrefix() {
- return envelopePrefix;
+
+ public void setEnvelopeQName(QName name) {
+ if (name.getPrefix().length() == 0) {
+ name = new QName(name.getNamespaceURI(), name.getLocalPart(), DEFAULT_ENV_PREFIX);
+ }
+ this.envelopeQName = name;
}
}
Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java?rev=1161199&r1=1161198&r2=1161199&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java (original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigInHandler.java Wed Aug 24 16:46:55 2011
@@ -28,8 +28,6 @@ import javax.xml.stream.XMLStreamReader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.jaxrs.ext.RequestHandler;
@@ -56,6 +54,7 @@ public class XmlSigInHandler extends Abs
this.removeSignature = remove;
}
+
public Response handleRequest(Message message, ClassResourceInfo resourceClass) {
Document doc = getDocument(message);
@@ -66,7 +65,7 @@ public class XmlSigInHandler extends Abs
Element root = doc.getDocumentElement();
Element sigElement = getSignatureElement(root);
if (sigElement == null) {
- throwFault("Enveloped Signature is not available", null);
+ throwFault("XML Signature is not available", null);
}
Crypto crypto = null;
@@ -84,8 +83,9 @@ public class XmlSigInHandler extends Abs
throwFault("Crypto can not be loaded", ex);
}
boolean valid = false;
+ Reference ref = null;
try {
- XMLSignature signature = new XMLSignature(sigElement, "");
+ XMLSignature signature = new XMLSignature(sigElement, "");
// See also WSS4J SAMLUtil.getCredentialFromKeyInfo
KeyInfo keyInfo = signature.getKeyInfo();
@@ -99,7 +99,8 @@ public class XmlSigInHandler extends Abs
}
}
// is this call redundant given that signature.checkSignatureValue uses References ?
- validateReference(root, signature);
+ ref = getReference(signature);
+ validateReference(root, ref);
// validate trust
new TrustValidator().validateTrust(crypto, cert, keyInfo.getPublicKey());
@@ -112,7 +113,8 @@ public class XmlSigInHandler extends Abs
}
if (removeSignature) {
if (!isEnveloping(root)) {
- root.removeAttribute("ID");
+ Element signedEl = getSignedElement(root, ref);
+ signedEl.removeAttribute("ID");
root.removeChild(sigElement);
} else {
Element actualBody = getActualBody(root);
@@ -138,24 +140,19 @@ public class XmlSigInHandler extends Abs
if (objectNode == null) {
throwFault("Object envelope is not available", null);
}
- NodeList list = objectNode.getChildNodes();
- for (int i = 0; i < list.getLength(); i++) {
- Node node = list.item(i);
- if (node instanceof Element) {
- objectNode.removeChild(node);
- return (Element)node;
- }
+ Element node = DOMUtils.getFirstElement(objectNode);
+ if (node == null) {
+ throwFault("No signed data is found", null);
}
- throwFault("No signed data is found", null);
- return null;
+ return node;
}
- private Element getSignatureElement(Element root) {
- if (isEnveloping(root)) {
- return root;
+ private Element getSignatureElement(Element sigParentElement) {
+ if (isEnveloping(sigParentElement)) {
+ return sigParentElement;
}
- return getNode(root, Constants.SignatureSpecNS, "Signature", 0);
+ return DOMUtils.getFirstChildWithName(sigParentElement, Constants.SignatureSpecNS, "Signature");
}
protected boolean isEnveloping(Element root) {
@@ -163,18 +160,21 @@ public class XmlSigInHandler extends Abs
&& "Signature".equals(root.getLocalName());
}
-
- protected void validateReference(Element root, XMLSignature sig) {
- Reference ref = null;
+ protected Reference getReference(XMLSignature sig) {
int count = sig.getSignedInfo().getLength();
if (count != 1) {
throwFault("Multiple Signature Reference are not currently supported", null);
}
try {
- ref = sig.getSignedInfo().item(0);
+ return sig.getSignedInfo().item(0);
} catch (XMLSecurityException ex) {
throwFault("Signature Reference is not available", ex);
}
+ return null;
+ }
+
+ protected void validateReference(Element root, Reference ref) {
+ boolean detached = false;
if (!isEnveloping(root)) {
String rootId = root.getAttribute("ID");
String refId = ref.getURI();
@@ -182,17 +182,25 @@ public class XmlSigInHandler extends Abs
// or fragment must be expected ?
return;
}
- if (!refId.startsWith("#") || refId.length() <= 1 || !refId.substring(1).equals(rootId)) {
+ if (!refId.startsWith("#") || refId.length() <= 1) {
+ throwFault("Only local Signature References are supported", null);
+ }
+
+ Element signedEl = getSignedElement(root, ref);
+ if (signedEl != null) {
+ detached = signedEl != root;
+ } else {
throwFault("Signature Reference ID is invalid", null);
}
}
+
Transforms transforms = null;
try {
transforms = ref.getTransforms();
} catch (XMLSecurityException ex) {
throwFault("Signature transforms can not be obtained", ex);
}
- if (!isEnveloping(root)) {
+ if (!isEnveloping(root) && !detached) {
boolean isEnveloped = false;
for (int i = 0; i < transforms.getLength(); i++) {
try {
@@ -210,4 +218,15 @@ public class XmlSigInHandler extends Abs
}
}
}
+
+ private Element getSignedElement(Element root, Reference ref) {
+ String rootId = root.getAttribute("ID");
+ String expectedID = ref.getURI().substring(1);
+
+ if (!expectedID.equals(rootId)) {
+ return (Element)DOMUtils.findChildWithAtt(root, null, "ID", expectedID);
+ } else {
+ return root;
+ }
+ }
}
Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigOutInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigOutInterceptor.java?rev=1161199&r1=1161198&r2=1161199&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigOutInterceptor.java (original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/xml/XmlSigOutInterceptor.java Wed Aug 24 16:46:55 2011
@@ -23,6 +23,8 @@ import java.security.cert.X509Certificat
import java.util.UUID;
import java.util.logging.Logger;
+import javax.xml.namespace.QName;
+
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -30,6 +32,7 @@ import org.w3c.dom.Element;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.helpers.DOMUtils;
+import org.apache.cxf.helpers.XMLUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.rs.security.common.CryptoLoader;
import org.apache.cxf.rs.security.common.SecurityUtils;
@@ -44,9 +47,14 @@ import org.opensaml.xml.signature.Signat
public class XmlSigOutInterceptor extends AbstractXmlSecOutInterceptor {
+ public static final String DEFAULT_ENV_PREFIX = "env";
+ public static final QName DEFAULT_ENV_QNAME =
+ new QName("http://org.apache.cxf/rs/env", "Envelope", DEFAULT_ENV_PREFIX);
+
private static final Logger LOG =
LogUtils.getL7dLogger(XmlSigOutInterceptor.class);
+ private QName envelopeQName;
private boolean enveloping;
private String defaultSigAlgo = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1;
private String digestAlgo = Constants.ALGO_ID_DIGEST_SHA1;
@@ -69,13 +77,17 @@ public class XmlSigOutInterceptor extend
protected Document processDocument(Message message, Document doc)
throws Exception {
- return createEnvelopedSignature(message, doc);
+ return createSignature(message, doc);
}
// enveloping & detached sigs will be supported too
- private Document createEnvelopedSignature(Message message, Document doc)
+ private Document createSignature(Message message, Document doc)
throws Exception {
+ if (enveloping && envelopeQName != null) {
+ throw new IllegalStateException("Enveloping XMLSignature can not have custom envelope names");
+ }
+
String userNameKey = SecurityConstants.SIGNATURE_USERNAME;
CryptoLoader loader = new CryptoLoader();
@@ -119,6 +131,8 @@ public class XmlSigOutInterceptor extend
XMLSignature sig = null;
if (enveloping) {
sig = prepareEnvelopingSignature(doc, id, referenceId, sigAlgo);
+ } else if (envelopeQName != null) {
+ sig = prepareDetachedSignature(doc, id, referenceId, sigAlgo);
} else {
sig = prepareEnvelopedSignature(doc, id, referenceId, sigAlgo);
}
@@ -153,6 +167,31 @@ public class XmlSigOutInterceptor extend
return sig;
}
+ private XMLSignature prepareDetachedSignature(Document doc,
+ String id,
+ String referenceId,
+ String sigAlgo) throws Exception {
+ Element docEl = doc.getDocumentElement();
+ Document newDoc = DOMUtils.createDocument();
+ doc.removeChild(docEl);
+ newDoc.adoptNode(docEl);
+ docEl.setAttribute("ID", id);
+
+ Element root = newDoc.createElementNS(envelopeQName.getNamespaceURI(),
+ envelopeQName.getPrefix() + ":" + envelopeQName.getLocalPart());
+ root.appendChild(docEl);
+ newDoc.appendChild(root);
+
+ XMLSignature sig = new XMLSignature(newDoc, "", sigAlgo);
+ root.appendChild(sig.getElement());
+
+ Transforms transforms = new Transforms(newDoc);
+ transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
+
+ sig.addDocument(referenceId, transforms, digestAlgo);
+ return sig;
+ }
+
private XMLSignature prepareEnvelopedSignature(Document doc,
String id,
String referenceURI,
@@ -168,4 +207,15 @@ public class XmlSigOutInterceptor extend
sig.addDocument(referenceURI, transforms, digestAlgo);
return sig;
}
+
+ public void setEnvelopeName(String expandedName) {
+ setEnvelopeQName(XMLUtils.convertStringToQName(expandedName, DEFAULT_ENV_PREFIX));
+ }
+
+ public void setEnvelopeQName(QName name) {
+ if (name.getPrefix().length() == 0) {
+ name = new QName(name.getNamespaceURI(), name.getLocalPart(), DEFAULT_ENV_PREFIX);
+ }
+ this.envelopeQName = name;
+ }
}