Author: alessio.soldano(a)jboss.com
Date: 2012-07-27 12:20:28 -0400 (Fri, 27 Jul 2012)
New Revision: 16554
Added:
stack/cxf/branches/jbossws-cxf-3.1.2/modules/server/src/main/java/org/jboss/wsf/stack/cxf/StAXUtils.java
Modified:
stack/cxf/branches/jbossws-cxf-3.1.2/modules/server/src/main/java/org/jboss/wsf/stack/cxf/DescriptorDeploymentAspect.java
Log:
[JBPAPP-9224] Workaround for preventing potentially vulnerable scenarios
Modified:
stack/cxf/branches/jbossws-cxf-3.1.2/modules/server/src/main/java/org/jboss/wsf/stack/cxf/DescriptorDeploymentAspect.java
===================================================================
---
stack/cxf/branches/jbossws-cxf-3.1.2/modules/server/src/main/java/org/jboss/wsf/stack/cxf/DescriptorDeploymentAspect.java 2012-07-27
11:04:16 UTC (rev 16553)
+++
stack/cxf/branches/jbossws-cxf-3.1.2/modules/server/src/main/java/org/jboss/wsf/stack/cxf/DescriptorDeploymentAspect.java 2012-07-27
16:20:28 UTC (rev 16554)
@@ -21,21 +21,29 @@
*/
package org.jboss.wsf.stack.cxf;
+import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
+
import java.io.IOException;
+import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
+import javax.jws.WebService;
+import javax.xml.stream.XMLStreamReader;
import javax.xml.ws.BindingType;
+import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.soap.MTOM;
import javax.xml.ws.soap.SOAPBinding;
import org.jboss.logging.Logger;
import org.jboss.wsf.spi.deployment.ArchiveDeployment;
import org.jboss.wsf.spi.deployment.Deployment;
+import org.jboss.wsf.spi.deployment.Deployment.DeploymentType;
import org.jboss.wsf.spi.deployment.DeploymentAspect;
import org.jboss.wsf.spi.deployment.Endpoint;
-import org.jboss.wsf.spi.deployment.Deployment.DeploymentType;
import org.jboss.wsf.stack.cxf.metadata.services.DDBeans;
import org.jboss.wsf.stack.cxf.metadata.services.DDEndpoint;
@@ -71,7 +79,7 @@
cxfURL = generateCXFConfigFromDeployment(dep);
}
putCXFConfigToDeployment(dep, cxfURL);
-
+ checkCVE20122379(dep, cxfURL);
}
@Override
@@ -96,25 +104,7 @@
*/
private URL getCXFConfigFromDeployment(Deployment dep)
{
- DeploymentType depType = dep.getType();
-
- String metadir;
- if (depType == DeploymentType.JAXWS_EJB3)
- {
- // expected resource location for EJB3 deployments
- metadir = "META-INF";
- }
- else if (depType == DeploymentType.JAXWS_JSE)
- {
- // expected resource location for POJO deployments
- metadir = "WEB-INF";
- }
- else
- {
- // only POJO and EJB3 deployments are supported
- throw new IllegalStateException("Unsupported deployment type: " +
depType);
- }
-
+ final String metadir = getMetaDir(dep);
URL cxfURL = null;
try
{
@@ -131,6 +121,26 @@
return cxfURL;
}
+ private String getMetaDir(Deployment dep) {
+
+ DeploymentType depType = dep.getType();
+ if (depType == DeploymentType.JAXWS_EJB3)
+ {
+ // expected resource location for EJB3 deployments
+ return "META-INF";
+ }
+ else if (depType == DeploymentType.JAXWS_JSE)
+ {
+ // expected resource location for POJO deployments
+ return "WEB-INF";
+ }
+ else
+ {
+ // only POJO and EJB3 deployments are supported
+ throw new IllegalStateException("Unsupported deployment type: " +
depType);
+ }
+ }
+
/**
* Generated CXF descriptor from deployment
* @param dep deployment
@@ -162,7 +172,6 @@
ddep.setInvoker(invokerJSE);
}
-
log.info("Add " + ddep);
dd.addEndpoint(ddep);
}
@@ -210,5 +219,129 @@
return mtomEnabled;
}
+
+ private void checkCVE20122379(Deployment dep, URL cxfURL)
+ {
+ try {
+ Set<String> wsdlLocations = new HashSet<String>();
+ //first check jbossws-cxf.xml
+ Set<String> endpoints = checkAssertionsAndGet(cxfURL,
"http://cxf.apache.org/jaxws", "endpoint", "implementor");
+ ClassLoader cl = dep.getRuntimeClassLoader();
+ if (cl == null) {
+ cl = dep.getInitialClassLoader();
+ }
+ System.out.println("** CL: " + cl);
+ for (String ep : endpoints)
+ {
+ Class<?> clazz = cl.loadClass(ep);
+ String wl = null;
+ if (clazz.isAnnotationPresent(WebService.class)) {
+ WebService wsa = clazz.getAnnotation(WebService.class);
+ wl = wsa.wsdlLocation();
+ String epIf = wsa.endpointInterface();
+ if(epIf != null && !epIf.isEmpty()) {
+ Class<?> epIfClass = cl.loadClass(epIf);
+ WebService epIfWsa = epIfClass.getAnnotation(WebService.class);
+ if (epIfWsa != null && epIfWsa.wsdlLocation() != null
&& !epIfWsa.wsdlLocation().isEmpty()) {
+ wl = epIfWsa.wsdlLocation();
+ }
+ }
+ } else {
+ WebServiceProvider wsp = clazz.getAnnotation(WebServiceProvider.class);
+ wl = wsp.wsdlLocation();
+ }
+ if (wl != null && !wl.trim().isEmpty()) {
+ wsdlLocations.add(wl);
+ }
+ }
+ //then check wsdl files for contract first endpoints
+ for (String w : wsdlLocations) {
+ try
+ {
+ ArchiveDeployment archDep = (ArchiveDeployment)dep;
+ URL wsdlURL = archDep.getResourceResolver().resolve(w);
+ checkAssertionsAndGet(wsdlURL, null, null, null);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Set<String> checkAssertionsAndGet(URL cxfUrl, String searchNS, String
searchLocalName, String searchAttributeName) throws Exception
+ {
+ log.info("* checking... " + cxfUrl);
+ InputStream is = null;
+ XMLStreamReader reader = null;
+ Set<String> endpoints = new HashSet<String>();
+ final boolean search = searchNS != null || searchLocalName != null ||
searchAttributeName != null;
+ try
+ {
+ is = cxfUrl.openStream();
+ reader = StAXUtils.createXMLStreamReader(is);
+ while (reader.hasNext())
+ {
+ switch (reader.next())
+ {
+ case START_ELEMENT:
+ {
+ if (StAXUtils.match(reader, NAMESPACES, ASSERTIONS))
+ {
+ throw new RuntimeException("WS-Security Policy SupportingTokens
not allowed due to known security vulnerability! URL: " + cxfUrl);
+ }
+ else if (search && StAXUtils.match(reader, searchNS,
searchLocalName))
+ {
+ String e = reader.getAttributeValue(null,
searchAttributeName).trim();
+ System.out.println("--> " + e);
+ endpoints.add(e);
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ try {
+ reader.close();
+ } catch (Exception e) {}
+ try {
+ is.close();
+ } catch (Exception e) {}
+ }
+ return endpoints;
+ }
+
+ private static final String SP_NS_11 =
"http://schemas.xmlsoap.org/ws/2005/02/securitypolicy";
+ private static final String SP_NS_12 =
"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702";
+ private static final String SP_NS_13 =
"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200802";
+ private static final String SUPPORTING_TOKENS = "SupportingTokens";
+ private static final String SIGNED_SUPPORTING_TOKENS =
"SignedSupportingTokens";
+ private static final String ENDORSING_SUPPORTING_TOKENS =
"EndorsingSupportingTokens";
+ private static final String SIGNED_ENDORSING_SUPPORTING_TOKENS =
"SignedEndorsingSupportingTokens";
+ private static final String SIGNED_ENCRYPTED_SUPPORTING_TOKENS =
"SignedEncryptedSupportingTokens";
+ private static final String ENCRYPTED_SUPPORTING_TOKENS =
"EncryptedSupportingTokens";
+ private static final String ENDORSING_ENCRYPTED_SUPPORTING_TOKENS =
"EndorsingEncryptedSupportingTokens";
+ private static final String SIGNED_ENDORSING_ENCRYPTED_SUPPORTING_TOKENS =
"SignedEndorsingEncryptedSupportingTokens";
+ private static String[] NAMESPACES = new String[3];
+ private static String[] ASSERTIONS = new String[8];
+ static {
+ NAMESPACES[0] = SP_NS_11;
+ NAMESPACES[1] = SP_NS_12;
+ NAMESPACES[2] = SP_NS_13;
+ ASSERTIONS[0] = SUPPORTING_TOKENS;
+ ASSERTIONS[1] = SIGNED_SUPPORTING_TOKENS;
+ ASSERTIONS[2] = ENDORSING_SUPPORTING_TOKENS;
+ ASSERTIONS[3] = SIGNED_ENDORSING_SUPPORTING_TOKENS;
+ ASSERTIONS[4] = SIGNED_ENCRYPTED_SUPPORTING_TOKENS;
+ ASSERTIONS[5] = ENCRYPTED_SUPPORTING_TOKENS;
+ ASSERTIONS[6] = ENDORSING_ENCRYPTED_SUPPORTING_TOKENS;
+ ASSERTIONS[7] = SIGNED_ENDORSING_ENCRYPTED_SUPPORTING_TOKENS;
+ }
}
Added:
stack/cxf/branches/jbossws-cxf-3.1.2/modules/server/src/main/java/org/jboss/wsf/stack/cxf/StAXUtils.java
===================================================================
---
stack/cxf/branches/jbossws-cxf-3.1.2/modules/server/src/main/java/org/jboss/wsf/stack/cxf/StAXUtils.java
(rev 0)
+++
stack/cxf/branches/jbossws-cxf-3.1.2/modules/server/src/main/java/org/jboss/wsf/stack/cxf/StAXUtils.java 2012-07-27
16:20:28 UTC (rev 16554)
@@ -0,0 +1,210 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.wsf.stack.cxf;
+
+import java.io.InputStream;
+import java.util.ResourceBundle;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLResolver;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+/**
+ * StAX utils
+ *
+ * @author alessio.soldano(a)jboss.com
+ * @since 27-Nov-2010
+ */
+public class StAXUtils
+{
+ private static final BlockingQueue<XMLInputFactory> INPUT_FACTORY_POOL;
+
+ static
+ {
+ int i = 10;
+ try
+ {
+ String s = System.getProperty("org.jboss.ws.staxutils.pool-size",
"10");
+ i = Integer.parseInt(s);
+ }
+ catch (Throwable t)
+ {
+ i = 10;
+ }
+ if (i <= 0)
+ {
+ i = 10;
+ }
+ INPUT_FACTORY_POOL = new LinkedBlockingQueue<XMLInputFactory>(i);
+ }
+
+ /**
+ * Return a new factory so that the caller can set sticky parameters.
+ * @param nsAware
+ * @return
+ */
+ public static XMLInputFactory createXMLInputFactory(boolean nsAware)
+ {
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, nsAware);
+ factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+ factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES,
Boolean.FALSE);
+ factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES,
Boolean.FALSE);
+ factory.setXMLResolver(new XMLResolver()
+ {
+ public Object resolveEntity(String publicID, String systemID, String baseURI,
String namespace)
+ throws XMLStreamException
+ {
+ throw new
XMLStreamException("READING_EXTERNAL_ENTITIES_IS_DISABLED");
+ }
+ });
+ return factory;
+ }
+
+ private static XMLInputFactory getXMLInputFactory()
+ {
+ XMLInputFactory f = INPUT_FACTORY_POOL.poll();
+ if (f == null)
+ {
+ f = createXMLInputFactory(true);
+ }
+ return f;
+ }
+
+ private static void returnXMLInputFactory(XMLInputFactory factory)
+ {
+ INPUT_FACTORY_POOL.offer(factory);
+ }
+
+ public static XMLStreamReader createXMLStreamReader(InputStream in)
+ {
+ XMLInputFactory factory = getXMLInputFactory();
+ try
+ {
+ return factory.createXMLStreamReader(in);
+ }
+ catch (XMLStreamException e)
+ {
+ throw new RuntimeException("Could not parse stream", e);
+ }
+ finally
+ {
+ returnXMLInputFactory(factory);
+ }
+ }
+
+ public static boolean match(XMLStreamReader reader, QName name)
+ {
+ return reader.getName().equals(name);
+ }
+
+ public static boolean match(XMLStreamReader reader, String namespace, String
localName)
+ {
+ QName name = reader.getName();
+ return localName.equals(name.getLocalPart()) &&
namespace.equals(name.getNamespaceURI());
+ }
+
+ public static boolean match(XMLStreamReader reader, String[] namespaces, String[]
localNames)
+ {
+ QName name = reader.getName();
+ boolean matchedNS = false;
+ for (String n : namespaces) {
+ if (!matchedNS && n.equals(name.getNamespaceURI())) {
+ matchedNS = true;
+ }
+ }
+ if (matchedNS) {
+ for (String l : localNames) {
+ if (l.equals(name.getLocalPart())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static String elementAsString(XMLStreamReader reader) throws
XMLStreamException
+ {
+ String elementtext = reader.getElementText();
+ return elementtext == null ? null : elementtext.trim();
+ }
+
+ public static QName elementAsQName(XMLStreamReader reader) throws XMLStreamException
+ {
+ String text = elementAsString(reader);
+ return stringToQName(reader, text, reader.getNamespaceURI());
+ }
+
+ public static boolean elementAsBoolean(XMLStreamReader reader) throws
XMLStreamException
+ {
+ String text = elementAsString(reader);
+ return Boolean.parseBoolean(text);
+ }
+
+ public static int elementAsInt(XMLStreamReader reader) throws XMLStreamException
+ {
+ String text = elementAsString(reader);
+ return Integer.parseInt(text);
+ }
+
+ public static QName attributeAsQName(XMLStreamReader reader, String namespace, String
localName) throws XMLStreamException
+ {
+ String text = reader.getAttributeValue(namespace, localName);
+ return stringToQName(reader, text, reader.getNamespaceURI());
+ }
+
+ public static QName attributeAsQName(XMLStreamReader reader, String namespace, String
localName, String targetNS) throws XMLStreamException
+ {
+ String text = reader.getAttributeValue(namespace, localName);
+ return stringToQName(reader, text, targetNS);
+ }
+
+ private static QName stringToQName(XMLStreamReader reader, String text, String
defaultNS)
+ {
+ String localPart = text.substring(text.indexOf(':') + 1, text.length());
+ int i = text.indexOf(':');
+ String prefix = i < 0 ? null : text.substring(0, i);
+ String namespaceURI = prefix == null ? defaultNS : reader.getNamespaceURI(prefix);
+ return prefix == null ? new QName(namespaceURI, localPart) : new
QName(namespaceURI, localPart, prefix);
+ }
+
+ public static int nextElement(XMLStreamReader reader)
+ {
+ try
+ {
+ int x = reader.next();
+ while (x != XMLStreamReader.START_ELEMENT && x !=
XMLStreamReader.END_ELEMENT && reader.hasNext())
+ {
+ x = reader.next();
+ }
+ return x;
+ }
+ catch (XMLStreamException e)
+ {
+ throw new RuntimeException("COULDN'T_PARSE_STREAM", e);
+ }
+ }
+}