From 8c9bbcb94a466eac745942ff16245958cc88da55 Mon Sep 17 00:00:00 2001 From: Thomas Bayer Date: Thu, 14 Nov 2024 14:56:50 +0100 Subject: [PATCH] Refactoring --- .../com/predic8/membrane/core/Constants.java | 8 + .../interceptor/RelocatingInterceptor.java | 12 +- .../core/interceptor/WSDLInterceptor.java | 333 +++++----- .../soap/SampleSoapServiceInterceptor.java | 57 +- .../membrane/core/rules/SOAPProxy.java | 603 +++++++++--------- .../membrane/core/ws/relocator/Relocator.java | 41 +- .../com/predic8/membrane/core/UnitTests.java | 130 ++-- .../core/interceptor/WSDLInterceptorTest.java | 100 ++- .../membrane/core/rules/SOAPProxyTest.java | 50 ++ .../core/ws/SoapProxyInvocationTest.java | 82 +++ .../core/ws/relocator/RelocatorTest.java | 24 +- .../test/resources/ws/cities-2-services.wsdl | 55 ++ core/src/test/resources/ws/cities.wsdl | 50 ++ 13 files changed, 877 insertions(+), 668 deletions(-) create mode 100644 core/src/test/java/com/predic8/membrane/core/rules/SOAPProxyTest.java create mode 100644 core/src/test/java/com/predic8/membrane/core/ws/SoapProxyInvocationTest.java create mode 100644 core/src/test/resources/ws/cities-2-services.wsdl create mode 100644 core/src/test/resources/ws/cities.wsdl diff --git a/core/src/main/java/com/predic8/membrane/core/Constants.java b/core/src/main/java/com/predic8/membrane/core/Constants.java index f2f8ce03cb..640b3808cb 100644 --- a/core/src/main/java/com/predic8/membrane/core/Constants.java +++ b/core/src/main/java/com/predic8/membrane/core/Constants.java @@ -17,6 +17,7 @@ import com.predic8.membrane.core.http.*; import com.predic8.membrane.core.interceptor.rest.*; +import javax.xml.namespace.*; import java.io.*; import java.util.*; @@ -58,6 +59,13 @@ public class Constants { public static final String WSDL_SOAP11_NS = "http://schemas.xmlsoap.org/wsdl/soap/"; public static final String WSDL_SOAP12_NS = "http://schemas.xmlsoap.org/wsdl/soap12/"; public static final String WSDL_HTTP_NS = "http://schemas.xmlsoap.org/wsdl/http/"; + + public static final QName WSDL11_ADDRESS_SOAP11 = new QName(WSDL_SOAP11_NS, + "address"); + public static final QName WSDL11_ADDRESS_SOAP12 = new QName(WSDL_SOAP12_NS, + "address"); + public static final QName WSDL11_ADDRESS_HTTP = new QName(WSDL_HTTP_NS, "address"); + public static final String WADL_NS = "http://wadl.dev.java.net/2009/02"; public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema"; diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/RelocatingInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/RelocatingInterceptor.java index eb45bb1c4c..51381b4d6a 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/RelocatingInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/RelocatingInterceptor.java @@ -25,6 +25,8 @@ import javax.xml.stream.XMLStreamException; import java.io.StringWriter; +import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE; + abstract public class RelocatingInterceptor extends AbstractInterceptor { private static Logger log = LoggerFactory.getLogger(RelocatingInterceptor.class.getName()); @@ -39,22 +41,22 @@ public Outcome handleResponse(Exchange exc) throws Exception { if (exc.getRule() instanceof ProxyRule) { log.debug(name + " ProxyRule found: No relocating done!"); - return Outcome.CONTINUE; + return CONTINUE; } if (!wasGetRequest(exc)) { log.debug(name + " HTTP method wasn't GET: No relocating done!"); - return Outcome.CONTINUE; + return CONTINUE; } if (!hasContent(exc)) { log.debug(name + " No Content: No relocating done!"); - return Outcome.CONTINUE; + return CONTINUE; } if (!exc.getResponse().isXML()) { log.debug(name + " Body contains no XML: No relocating done!"); - return Outcome.CONTINUE; + return CONTINUE; } try { @@ -62,7 +64,7 @@ public Outcome handleResponse(Exchange exc) throws Exception { } catch (XMLStreamException e) { throw new Exception("while rewriting " + exc.getRequestURI(), e); } - return Outcome.CONTINUE; + return CONTINUE; } abstract void rewrite(Exchange exc) throws Exception; diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java index 7e3a9a0b30..2ef9930596 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java @@ -23,6 +23,7 @@ import com.predic8.membrane.core.transport.http.HttpClient; import com.predic8.membrane.core.util.MessageUtil; import com.predic8.membrane.core.ws.relocator.Relocator; +import org.jetbrains.annotations.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,172 +34,180 @@ import java.net.URLDecoder; import static com.predic8.membrane.core.Constants.*; +import static com.predic8.membrane.core.interceptor.Interceptor.Flow.Set.RESPONSE; /** - * @description - *

The wsdlRewriter rewrites endpoint addresses of services and XML Schema locations in WSDL documents.

+ * @description

The wsdlRewriter rewrites endpoint addresses of services and XML Schema locations in WSDL documents.

* @topic 8. SOAP based Web Services */ -@MCElement(name="wsdlRewriter") +@MCElement(name = "wsdlRewriter") public class WSDLInterceptor extends RelocatingInterceptor { - private static Logger log = LoggerFactory.getLogger(WSDLInterceptor.class.getName()); - - private String registryWSDLRegisterURL; - private boolean rewriteEndpoint = true; - private HttpClient hc; - - public WSDLInterceptor() { - name = "WSDL Rewriting Interceptor"; - setFlow(Flow.Set.RESPONSE); - } - - @Override - public void init(Router router) throws Exception { - super.init(router); - hc = router.getHttpClientFactory().createClient(null); - } - - @Override - protected void rewrite(Exchange exc) throws Exception, IOException { - - log.debug("Changing endpoint address in WSDL"); - - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - - Relocator relocator = new Relocator(new OutputStreamWriter(stream, - exc.getResponse().getCharset()), getLocationProtocol(), getLocationHost(exc), - getLocationPort(exc), exc.getHandler().getContextPath(exc), pathRewriter); - - if (rewriteEndpoint) { - relocator.getRelocatingAttributes().put( - new QName(WSDL_SOAP11_NS, "address"), "location"); - relocator.getRelocatingAttributes().put( - new QName(WSDL_SOAP12_NS, "address"), "location"); - relocator.getRelocatingAttributes().put( - new QName(WSDL_HTTP_NS, "address"), "location"); - } - relocator.getRelocatingAttributes().put(new QName(XSD_NS, "import"), - "schemaLocation"); - relocator.getRelocatingAttributes().put(new QName(XSD_NS, "include"), - "schemaLocation"); - - relocator.relocate(new InputStreamReader(exc.getResponse().getBodyAsStreamDecoded(), exc.getResponse().getCharset())); - - if (relocator.isWsdlFound()) { - registerWSDL(exc); - } - exc.getResponse().setBodyContent(stream.toByteArray()); - } - - private void registerWSDL(Exchange exc) { - if (registryWSDLRegisterURL == null) - return; - - StringBuilder buf = new StringBuilder(); - buf.append(registryWSDLRegisterURL); - buf.append("?wsdl="); - - try { - buf.append(URLDecoder.decode(getWSDLURL(exc), "US-ASCII")); - } catch (UnsupportedEncodingException e) { - // ignored - } - - callRegistry(buf.toString()); - - log.debug(buf.toString()); - } - - private void callRegistry(String uri) { - try { - Response res = hc.call(createExchange(uri)).getResponse(); - if (res.getStatusCode() != 200) - log.warn("{}",res); - } catch (Exception e) { - log.error("", e); - } - } - - private Exchange createExchange(String uri) throws MalformedURLException { - URL url = new URL(uri); - Request req = MessageUtil.getGetRequest(getCompletePath(url)); - req.getHeader().setHost(url.getHost()); - Exchange exc = new Exchange(null); - exc.setRequest(req); - exc.getDestinations().add(uri); - return exc; - } - - private String getCompletePath(URL url) { - if (url.getQuery() == null) - return url.getPath(); - - return url.getPath() + "?" + url.getQuery(); - } - - private String getWSDLURL(Exchange exc) { - StringBuilder buf = new StringBuilder(); - buf.append(getLocationProtocol()); - buf.append("://"); - buf.append(getLocationHost(exc)); - if (getLocationPort(exc) != 80) { - buf.append(":"); - buf.append(getLocationPort(exc)); - } - buf.append("/"); - buf.append(exc.getRequest().getUri()); - return buf.toString(); - } - - @MCAttribute - public void setRegistryWSDLRegisterURL(String registryWSDLRegisterURL) { - this.registryWSDLRegisterURL = registryWSDLRegisterURL; - } - - public String getRegistryWSDLRegisterURL() { - return registryWSDLRegisterURL; - } - - @Override - public String getShortDescription() { - return "Rewrites SOAP endpoint addresses and XML Schema locations in WSDL and XSD documents."; - } - - public void setRewriteEndpoint(boolean rewriteEndpoint) { - this.rewriteEndpoint = rewriteEndpoint; - } - - /** - * @description The protocol the endpoint should be changed to. - * @default Don't change the endpoint's protocol. - * @example http - */ - @MCAttribute - @Override - public void setProtocol(String protocol) { - super.setProtocol(protocol); - } - - /** - * @description The host the endpoint should be changed to. - * @default Don't change the endpoint's host. - * @example localhost - */ - @MCAttribute - @Override - public void setHost(String host) { - super.setHost(host); - } - - /** - * @description The port the endpoint should be changed to. - * @default Don't change the endpoint's port. - * @example 4000 - */ - @MCAttribute - @Override - public void setPort(String port) { - super.setPort(port); - } + public static final QName WSDL_11_SOAP_ADDRESS_QNAME = new QName(WSDL_SOAP11_NS, "address"); + public static final QName WSDL_12_SOAP_ADDRESS_QNAME = new QName(WSDL_SOAP12_NS, "address"); + public static final QName HTTP_SOAP_ADDRESS_QNAME = new QName(WSDL_HTTP_NS, "address"); + public static final QName XSD_IMPORT_QNAME = new QName(XSD_NS, "import"); + public static final QName XSD_INCLUDE_QNAME = new QName(XSD_NS, "include"); + + private static Logger log = LoggerFactory.getLogger(WSDLInterceptor.class.getName()); + + private String registryWSDLRegisterURL; + private boolean rewriteEndpoint = true; + private HttpClient hc; + + public WSDLInterceptor() { + name = "WSDL Rewriting Interceptor"; + setFlow(RESPONSE); + } + + @Override + public void init(Router router) throws Exception { + super.init(router); + hc = router.getHttpClientFactory().createClient(null); + } + + @Override + protected void rewrite(Exchange exc) throws Exception { + + log.debug("Changing endpoint address in WSDL"); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + Relocator relocator = getRelocator(exc, stream); + + relocator.relocate(new InputStreamReader(exc.getResponse().getBodyAsStreamDecoded(), exc.getResponse().getCharset())); + + if (relocator.isWsdlFound()) { + registerWSDL(exc); + } + + exc.getResponse().setBodyContent(stream.toByteArray()); + } + + private @NotNull Relocator getRelocator(Exchange exc, OutputStream stream) throws Exception { + Relocator relocator = new Relocator(new OutputStreamWriter(stream, + exc.getResponse().getCharset()), getLocationProtocol(), getLocationHost(exc), + getLocationPort(exc), exc.getHandler().getContextPath(exc), pathRewriter); + + if (rewriteEndpoint) { + relocator.getRelocatingAttributes().put(WSDL_11_SOAP_ADDRESS_QNAME, "location"); + relocator.getRelocatingAttributes().put(WSDL_12_SOAP_ADDRESS_QNAME, "location"); + relocator.getRelocatingAttributes().put(HTTP_SOAP_ADDRESS_QNAME, "location"); + } + + relocator.getRelocatingAttributes().put(XSD_IMPORT_QNAME, "schemaLocation"); + relocator.getRelocatingAttributes().put(XSD_INCLUDE_QNAME, "schemaLocation"); + return relocator; + } + + private void registerWSDL(Exchange exc) { + if (registryWSDLRegisterURL == null) + return; + + StringBuilder buf = new StringBuilder(); + buf.append(registryWSDLRegisterURL); + buf.append("?wsdl="); + + try { + buf.append(URLDecoder.decode(getWSDLURL(exc), "US-ASCII")); + } catch (UnsupportedEncodingException e) { + // ignored + } + + callRegistry(buf.toString()); + + log.debug(buf.toString()); + } + + private void callRegistry(String uri) { + try { + Response res = hc.call(createExchange(uri)).getResponse(); + if (res.getStatusCode() != 200) + log.warn("{}", res); + } catch (Exception e) { + log.error("", e); + } + } + + private Exchange createExchange(String uri) throws MalformedURLException { + URL url = new URL(uri); + Request req = MessageUtil.getGetRequest(getCompletePath(url)); + req.getHeader().setHost(url.getHost()); + Exchange exc = new Exchange(null); + exc.setRequest(req); + exc.getDestinations().add(uri); + return exc; + } + + private String getCompletePath(URL url) { + if (url.getQuery() == null) + return url.getPath(); + + return url.getPath() + "?" + url.getQuery(); + } + + private String getWSDLURL(Exchange exc) { + StringBuilder buf = new StringBuilder(); + buf.append(getLocationProtocol()); + buf.append("://"); + buf.append(getLocationHost(exc)); + if (getLocationPort(exc) != 80) { + buf.append(":"); + buf.append(getLocationPort(exc)); + } + buf.append("/"); + buf.append(exc.getRequest().getUri()); + return buf.toString(); + } + + @MCAttribute + public void setRegistryWSDLRegisterURL(String registryWSDLRegisterURL) { + this.registryWSDLRegisterURL = registryWSDLRegisterURL; + } + + public String getRegistryWSDLRegisterURL() { + return registryWSDLRegisterURL; + } + + @Override + public String getShortDescription() { + return "Rewrites SOAP endpoint addresses and XML Schema locations in WSDL and XSD documents."; + } + + public void setRewriteEndpoint(boolean rewriteEndpoint) { + this.rewriteEndpoint = rewriteEndpoint; + } + + /** + * @description The protocol the endpoint should be changed to. + * @default Don't change the endpoint's protocol. + * @example http + */ + @MCAttribute + @Override + public void setProtocol(String protocol) { + super.setProtocol(protocol); + } + + /** + * @description The host the endpoint should be changed to. + * @default Don't change the endpoint's host. + * @example localhost + */ + @MCAttribute + @Override + public void setHost(String host) { + super.setHost(host); + } + + /** + * @description The port the endpoint should be changed to. + * @default Don't change the endpoint's port. + * @example 4000 + */ + @MCAttribute + @Override + public void setPort(String port) { + super.setPort(port); + } } diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/soap/SampleSoapServiceInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/soap/SampleSoapServiceInterceptor.java index 4540f1b66a..fd6edf5c80 100644 --- a/core/src/main/java/com/predic8/membrane/core/interceptor/soap/SampleSoapServiceInterceptor.java +++ b/core/src/main/java/com/predic8/membrane/core/interceptor/soap/SampleSoapServiceInterceptor.java @@ -13,37 +13,28 @@ limitations under the License. */ package com.predic8.membrane.core.interceptor.soap; -import com.predic8.membrane.annot.MCElement; -import com.predic8.membrane.core.exchange.Exchange; -import com.predic8.membrane.core.http.Response; -import com.predic8.membrane.core.interceptor.AbstractInterceptor; -import com.predic8.membrane.core.interceptor.Outcome; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; +import com.predic8.membrane.annot.*; +import com.predic8.membrane.core.exchange.*; +import com.predic8.membrane.core.http.*; +import com.predic8.membrane.core.interceptor.*; +import org.w3c.dom.*; + +import javax.xml.parsers.*; import javax.xml.stream.*; -import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; -import javax.xml.transform.TransformerException; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.StringWriter; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Objects; -import java.util.regex.Pattern; - -import static com.predic8.membrane.core.Constants.SOAP11_NS; -import static com.predic8.membrane.core.http.Header.CONTENT_TYPE; +import javax.xml.stream.events.*; +import javax.xml.transform.*; +import java.io.*; +import java.util.*; +import java.util.regex.*; + +import static com.predic8.membrane.core.Constants.*; +import static com.predic8.membrane.core.http.Header.*; import static com.predic8.membrane.core.http.MimeType.*; -import static com.predic8.membrane.core.http.Response.ok; -import static com.predic8.membrane.core.interceptor.Outcome.RETURN; -import static com.predic8.membrane.core.openapi.util.Utils.getResourceAsStream; -import static com.predic8.membrane.core.util.XMLUtil.xml2string; -import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import static com.predic8.membrane.core.http.Response.*; +import static com.predic8.membrane.core.interceptor.Outcome.*; +import static com.predic8.membrane.core.openapi.util.Utils.*; +import static com.predic8.membrane.core.util.XMLUtil.*; +import static javax.xml.stream.XMLStreamConstants.*; @MCElement(name = "sampleSoapService") public class SampleSoapServiceInterceptor extends AbstractInterceptor { @@ -77,7 +68,7 @@ public Outcome handleRequest(Exchange exc) throws Exception { } private static Response createResourceNotFoundSOAPFault() throws Exception { - return ok(getSoapFault("Resource Not Found", "404", "Cannot parse SOAP message. Request should contain e.g. Bonn")).contentType(APPLICATION_XML).build(); + return ok(getSoapFault("Resource Not Found", "404", "Cannot parse SOAP message. Request should contain e.g. Bonn")).contentType(TEXT_XML).build(); } private static Response createGetCityResponse(Exchange exc) throws Exception { @@ -85,7 +76,7 @@ private static Response createGetCityResponse(Exchange exc) throws Exception { } private static Response createMethodNotAllowedSOAPFault() throws Exception { - return ok(getSoapFault("Method Not Allowed", "405", "Use POST to access the service.")).contentType(APPLICATION_XML).build(); + return ok(getSoapFault("Method Not Allowed", "405", "Use POST to access the service.")).contentType(TEXT_XML).build(); } private Response createWSDLResponse(Exchange exc) throws XMLStreamException, FileNotFoundException { @@ -176,8 +167,8 @@ public static String getSOAPAddress(Exchange exc) { return exc.getInboundProtocol() + "://" + exc.getRequest().getHeader().getHost() + getPathWithoutParam(exc.getOriginalRequestUri()); } - static String getPathWithoutParam(String exc) { - return exc.replaceAll("\\?.*$", ""); + static String getPathWithoutParam(String uri) { + return uri.replaceAll("\\?.*$", ""); } diff --git a/core/src/main/java/com/predic8/membrane/core/rules/SOAPProxy.java b/core/src/main/java/com/predic8/membrane/core/rules/SOAPProxy.java index 8233b69da0..4f0184cf3f 100644 --- a/core/src/main/java/com/predic8/membrane/core/rules/SOAPProxy.java +++ b/core/src/main/java/com/predic8/membrane/core/rules/SOAPProxy.java @@ -13,309 +13,326 @@ limitations under the License. */ package com.predic8.membrane.core.rules; -import java.net.ConnectException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.UnknownHostException; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.predic8.membrane.annot.Required; - -import com.google.common.collect.Lists; -import com.predic8.membrane.annot.MCAttribute; -import com.predic8.membrane.annot.MCElement; -import com.predic8.membrane.core.Constants; -import com.predic8.membrane.core.Router; -import com.predic8.membrane.core.config.security.SSLParser; -import com.predic8.membrane.core.interceptor.Interceptor; -import com.predic8.membrane.core.interceptor.WSDLInterceptor; -import com.predic8.membrane.core.interceptor.rewrite.RewriteInterceptor; -import com.predic8.membrane.core.interceptor.server.WSDLPublisherInterceptor; -import com.predic8.membrane.core.interceptor.soap.WebServiceExplorerInterceptor; -import com.predic8.membrane.core.resolver.ResourceRetrievalException; -import com.predic8.membrane.core.resolver.HTTPSchemaResolver; -import com.predic8.membrane.core.resolver.ResolverMap; -import com.predic8.membrane.core.transport.http.client.HttpClientConfiguration; -import com.predic8.membrane.core.util.URLUtil; -import com.predic8.membrane.core.ws.relocator.Relocator.PathRewriter; -import com.predic8.wsdl.AbstractBinding; -import com.predic8.wsdl.Definitions; -import com.predic8.wsdl.Port; -import com.predic8.wsdl.Service; -import com.predic8.wsdl.WSDLParser; -import com.predic8.wsdl.WSDLParserContext; - -import javax.xml.namespace.QName; +import com.google.common.collect.*; +import com.predic8.membrane.annot.*; +import com.predic8.membrane.core.*; +import com.predic8.membrane.core.config.security.*; +import com.predic8.membrane.core.interceptor.*; +import com.predic8.membrane.core.interceptor.rewrite.*; +import com.predic8.membrane.core.interceptor.server.*; +import com.predic8.membrane.core.interceptor.soap.*; +import com.predic8.membrane.core.resolver.*; +import com.predic8.membrane.core.transport.http.client.*; +import com.predic8.membrane.core.util.*; +import com.predic8.wsdl.*; +import org.apache.commons.lang3.*; +import org.slf4j.*; + +import javax.xml.namespace.*; +import java.net.*; +import java.util.*; +import java.util.regex.*; import static com.predic8.membrane.core.Constants.*; /** * @description

- * A SOAP proxy can be deployed on front of a SOAP Web Service. It conceals the server and offers the same - * interface as the target server to its clients. - *

+ * A SOAP proxy can be deployed on front of a SOAP Web Service. It conceals the server and offers the same + * interface as the target server to its clients. + *

* @explanation If the WSDL referenced by the wsdl attribute is not available at startup, the <soapProxy> - * will become inactive. Through the admin console, reinitialization attempts can be triggered and, by - * default, the {@link Router} also periodically triggers such attempts. + * will become inactive. Through the admin console, reinitialization attempts can be triggered and, by + * default, the {@link Router} also periodically triggers such attempts. * @topic 2. Proxies */ -@MCElement(name="soapProxy") +@MCElement(name = "soapProxy") public class SOAPProxy extends AbstractServiceProxy { - private static final Logger log = LoggerFactory.getLogger(SOAPProxy.class.getName()); - private static final Pattern relativePathPattern = Pattern.compile("^./[^/?]*\\?"); - - // configuration attributes - protected String wsdl; - protected String portName; - protected String targetPath; - protected HttpClientConfiguration httpClientConfig; - - // set during initialization - protected ResolverMap resolverMap; - - public SOAPProxy() { - this.key = new ServiceProxyKey(80); - } - - @Override - protected AbstractProxy getNewInstance() { - return new SOAPProxy(); - } - - private void parseWSDL() throws Exception { - WSDLParserContext ctx = new WSDLParserContext(); - ctx.setInput(ResolverMap.combine(router.getBaseLocation(), wsdl)); - try { - WSDLParser wsdlParser = new WSDLParser(); - wsdlParser.setResourceResolver(resolverMap.toExternalResolver().toExternalResolver()); - - Definitions definitions = wsdlParser.parse(ctx); - - List services = definitions.getServices(); - if (services.size() != 1) - throw new IllegalArgumentException("There are " + services.size() + " services defined in the WSDL, but exactly 1 is required for soapProxy."); - Service service = services.get(0); - - if (StringUtils.isEmpty(name)) - name = StringUtils.isEmpty(service.getName()) ? definitions.getName() : service.getName(); - - List ports = service.getPorts(); - Port port = selectPort(ports, portName); - - String location = port.getAddress().getLocation(); - if (location == null) - throw new IllegalArgumentException("In the WSDL, there is no @location defined on the port."); - try { - URL url = new URL(location); - if (wsdl.startsWith("service:")) { - target.setUrl(wsdl.substring(0, wsdl.indexOf('/'))); - } else { - target.setHost(url.getHost()); - if (url.getPort() != -1) - target.setPort(url.getPort()); - else - target.setPort(url.getDefaultPort()); - } - if (key.getPath() == null) { - key.setUsePathPattern(true); - key.setPathRegExp(false); - key.setPath(url.getPath()); - } else { - String query = ""; - if(url.getQuery() != null){ - query = "?" + url.getQuery(); - } - targetPath = url.getPath()+ query; - } - if(location.startsWith("https")){ - SSLParser sslOutboundParser = new SSLParser(); - target.setSslParser(sslOutboundParser); - } - ((ServiceProxyKey)key).setMethod("*"); - } catch (MalformedURLException e) { - throw new IllegalArgumentException("WSDL endpoint location '"+location+"' is not an URL.", e); - } - } catch (Exception e) { - Throwable f = e; - while (f.getCause() != null && ! (f instanceof ResourceRetrievalException)) - f = f.getCause(); - if (f instanceof ResourceRetrievalException rre) { - if (rre.getStatus() >= 400) - throw rre; - Throwable cause = rre.getCause(); - if (cause != null) { - if (cause instanceof UnknownHostException) - throw (UnknownHostException) cause; - else if (cause instanceof ConnectException) - throw (ConnectException) cause; - } - } - throw new IllegalArgumentException("Could not download the WSDL '" + wsdl + "'.", e); - } - } - - public static Port selectPort(List ports, String portName) { - if (portName != null) { - for (Port port : ports) - if (portName.equals(port.getName())) - return port; - throw new IllegalArgumentException("No port with name '" + portName + "' found."); - } - return getPort(ports); - } - - private static Port getPort(List ports) { - Port port = getPortByNamespace(ports, WSDL_SOAP11_NS); - if (port == null) - port = getPortByNamespace(ports, WSDL_SOAP12_NS); - if (port == null) - throw new IllegalArgumentException("No SOAP/1.1 or SOAP/1.2 ports found in WSDL."); - return port; - } - - private static Port getPortByNamespace(List ports, String namespace) { - for (Port port : ports) { - try { - if (port.getBinding() == null) - continue; - if (port.getBinding().getBinding() == null) - continue; - AbstractBinding binding = port.getBinding().getBinding(); - if (!"http://schemas.xmlsoap.org/soap/http".equals(binding.getProperty("transport"))) - continue; - if (!namespace.equals(((QName)binding.getElementName()).getNamespaceURI())) - continue; - return port; - } catch (Exception e) { - log.warn("Error inspecting WSDL port binding.", e); - } - } - return null; - } - - private int automaticallyAddedInterceptorCount; - - public void configure() throws Exception { - - parseWSDL(); - // remove previously added interceptors - for(; automaticallyAddedInterceptorCount > 0; automaticallyAddedInterceptorCount--) - interceptors.remove(0); - - - // add interceptors (in reverse order) to position 0. - - WebServiceExplorerInterceptor sui = new WebServiceExplorerInterceptor(); - sui.setWsdl(wsdl); - sui.setPortName(portName); - interceptors.add(0, sui); - automaticallyAddedInterceptorCount++; - - boolean hasPublisher = getInterceptorOfType(WSDLPublisherInterceptor.class) != null; - if (!hasPublisher) { - WSDLPublisherInterceptor wp = new WSDLPublisherInterceptor(); - wp.setWsdl(wsdl); - interceptors.add(0, wp); - automaticallyAddedInterceptorCount++; - } - - WSDLInterceptor wsdlInterceptor = getInterceptorOfType(WSDLInterceptor.class); - boolean hasRewriter = wsdlInterceptor != null; - if (!hasRewriter) { - wsdlInterceptor = new WSDLInterceptor(); - interceptors.add(0, wsdlInterceptor); - automaticallyAddedInterceptorCount++; - } - if (key.getPath() != null) { - final String keyPath = key.getPath(); - final String name = URLUtil.getName(router.getUriFactory(), keyPath); - wsdlInterceptor.setPathRewriter(path2 -> { - try { - if (path2.contains("://")) { - return new URL(new URL(path2), keyPath).toString(); - } else { - Matcher m = relativePathPattern.matcher(path2); - return m.replaceAll("./" + name + "?"); - } - } catch (MalformedURLException e) { - log.error("Cannot parse URL " + path2); - } - return path2; - }); - } - - if (hasRewriter && !hasPublisher) - log.warn("A contains a , but no . Probably you want to insert a just after the . (Or, if this is a valid use case, please notify us at " + PRODUCT_CONTACT_EMAIL + ".)"); - - if (targetPath != null) { - RewriteInterceptor ri = new RewriteInterceptor(); - ri.setMappings(Lists.newArrayList(new RewriteInterceptor.Mapping("^" + Pattern.quote(key.getPath()), Matcher.quoteReplacement(targetPath), "rewrite"))); - interceptors.add(0, ri); - automaticallyAddedInterceptorCount++; - } - } - - @Override - public void init() throws Exception { - if (wsdl == null) { - return; - } - - resolverMap = router.getResolverMap(); - if (httpClientConfig != null) { - HTTPSchemaResolver httpSR = new HTTPSchemaResolver(router.getHttpClientFactory()); - httpSR.setHttpClientConfig(httpClientConfig); - resolverMap = resolverMap.clone(); - resolverMap.addSchemaResolver(httpSR); - } - - configure(); - super.init(); - } - - @SuppressWarnings("unchecked") - private T getInterceptorOfType(Class class1) { - for (Interceptor i : interceptors) - if (class1.isInstance(i)) - return (T) i; - return null; - } - - public String getWsdl() { - return wsdl; - } - - /** + + private static final Logger log = LoggerFactory.getLogger(SOAPProxy.class.getName()); + private static final Pattern relativePathPattern = Pattern.compile("^./[^/?]*\\?"); + + // configuration attributes + protected String wsdl; + protected String portName; + protected String targetPath; + protected HttpClientConfiguration httpClientConfig; + protected String serviceName; + + // set during initialization + protected ResolverMap resolverMap; + + public SOAPProxy() { + this.key = new ServiceProxyKey(80); + } + + @Override + protected AbstractProxy getNewInstance() { + return new SOAPProxy(); + } + + void parseWSDL() throws Exception { + WSDLParserContext ctx = new WSDLParserContext(); + ctx.setInput(ResolverMap.combine(router.getBaseLocation(), wsdl)); + + + WSDLParser wsdlParser = new WSDLParser(); + wsdlParser.setResourceResolver(resolverMap.toExternalResolver().toExternalResolver()); + + Definitions definitions = wsdlParser.parse(ctx); + + Service service = getService(definitions); + + setProxyName(service, definitions); + + List ports = service.getPorts(); + Port port = selectPort(ports, portName); + + String location = port.getAddress().getLocation(); + + if (location == null) + throw new IllegalArgumentException("In the WSDL, there is no @location defined on the port."); + + try { + + URL url = new URL(location); + + setTarget(url); + + if (key.getPath() == null) { + key.setUsePathPattern(true); + key.setPathRegExp(false); + key.setPath(url.getPath()); + } else { + String query = ""; + if (url.getQuery() != null) { + query = "?" + url.getQuery(); + } + targetPath = url.getPath() + query; + } + if (location.startsWith("https")) { + target.setSslParser(new SSLParser()); + } + + ((ServiceProxyKey) key).setMethod("*"); // GET and POST are used for SOAP + + } catch (MalformedURLException e) { + throw new IllegalArgumentException("WSDL endpoint location '" + location + "' is not an URL.", e); + } catch (Exception e) { + handleException(e); + } + } + + private static Service getService(Definitions definitions) { + List services = definitions.getServices(); + + + + if (services.size() == 1) + return services.get(0); + + throw new IllegalArgumentException("There are " + services.size() + " services defined in the WSDL, but exactly 1 is required for soapProxy."); + } + + private void handleException(Exception e) throws ResourceRetrievalException, UnknownHostException, ConnectException { + Throwable f = e; + while (f.getCause() != null && !(f instanceof ResourceRetrievalException)) + f = f.getCause(); + if (f instanceof ResourceRetrievalException rre) { + if (rre.getStatus() >= 400) + throw rre; + Throwable cause = rre.getCause(); + if (cause != null) { + if (cause instanceof UnknownHostException) + throw (UnknownHostException) cause; + else if (cause instanceof ConnectException) + throw (ConnectException) cause; + } + } + throw new IllegalArgumentException("Could not download the WSDL '" + wsdl + "'.", e); + } + + private void setTarget(URL url) { + if (wsdl.startsWith("service:")) { + target.setUrl(wsdl.substring(0, wsdl.indexOf('/'))); + } else { + target.setHost(url.getHost()); + if (url.getPort() != -1) + target.setPort(url.getPort()); + else + target.setPort(url.getDefaultPort()); + } + } + + private void setProxyName(Service service, Definitions definitions) { + if (StringUtils.isEmpty(name)) + name = StringUtils.isEmpty(service.getName()) ? definitions.getName() : service.getName(); + } + + public static Port selectPort(List ports, String portName) { + if (portName != null) { + for (Port port : ports) + if (portName.equals(port.getName())) + return port; + throw new IllegalArgumentException("No port with name '" + portName + "' found."); + } + return getPort(ports); + } + + private static Port getPort(List ports) { + Port port = getPortByNamespace(ports, WSDL_SOAP11_NS); + if (port == null) + port = getPortByNamespace(ports, WSDL_SOAP12_NS); + if (port == null) + throw new IllegalArgumentException("No SOAP/1.1 or SOAP/1.2 ports found in WSDL."); + return port; + } + + private static Port getPortByNamespace(List ports, String namespace) { + for (Port port : ports) { + try { + if (port.getBinding() == null) + continue; + if (port.getBinding().getBinding() == null) + continue; + AbstractBinding binding = port.getBinding().getBinding(); + if (!"http://schemas.xmlsoap.org/soap/http".equals(binding.getProperty("transport"))) + continue; + if (!namespace.equals(((QName) binding.getElementName()).getNamespaceURI())) + continue; + return port; + } catch (Exception e) { + log.warn("Error inspecting WSDL port binding.", e); + } + } + return null; + } + + private int automaticallyAddedInterceptorCount; + + public void configure() throws Exception { + + parseWSDL(); + // remove previously added interceptors + for (; automaticallyAddedInterceptorCount > 0; automaticallyAddedInterceptorCount--) + interceptors.remove(0); + + + // add interceptors (in reverse order) to position 0. + + WebServiceExplorerInterceptor sui = new WebServiceExplorerInterceptor(); + sui.setWsdl(wsdl); + sui.setPortName(portName); + interceptors.add(0, sui); + automaticallyAddedInterceptorCount++; + + boolean hasPublisher = getInterceptorOfType(WSDLPublisherInterceptor.class) != null; + if (!hasPublisher) { + WSDLPublisherInterceptor wp = new WSDLPublisherInterceptor(); + wp.setWsdl(wsdl); + interceptors.add(0, wp); + automaticallyAddedInterceptorCount++; + } + + WSDLInterceptor wsdlInterceptor = getInterceptorOfType(WSDLInterceptor.class); + boolean hasRewriter = wsdlInterceptor != null; + if (!hasRewriter) { + wsdlInterceptor = new WSDLInterceptor(); + interceptors.add(0, wsdlInterceptor); + automaticallyAddedInterceptorCount++; + } + if (key.getPath() != null) { + final String keyPath = key.getPath(); + final String name = URLUtil.getName(router.getUriFactory(), keyPath); + wsdlInterceptor.setPathRewriter(path2 -> { + try { + if (path2.contains("://")) { + return new URL(new URL(path2), keyPath).toString(); + } else { + Matcher m = relativePathPattern.matcher(path2); + return m.replaceAll("./" + name + "?"); + } + } catch (MalformedURLException e) { + log.error("Cannot parse URL " + path2); + } + return path2; + }); + } + + if (hasRewriter && !hasPublisher) + log.warn("A contains a , but no . Probably you want to insert a just after the . (Or, if this is a valid use case, please notify us at " + PRODUCT_CONTACT_EMAIL + ".)"); + + if (targetPath != null) { + RewriteInterceptor ri = new RewriteInterceptor(); + ri.setMappings(Lists.newArrayList(new RewriteInterceptor.Mapping("^" + Pattern.quote(key.getPath()), Matcher.quoteReplacement(targetPath), "rewrite"))); + interceptors.add(0, ri); + automaticallyAddedInterceptorCount++; + } + } + + @Override + public void init() throws Exception { + if (wsdl == null) { + return; + } + + resolverMap = router.getResolverMap(); + if (httpClientConfig != null) { + HTTPSchemaResolver httpSR = new HTTPSchemaResolver(router.getHttpClientFactory()); + httpSR.setHttpClientConfig(httpClientConfig); + resolverMap = resolverMap.clone(); + resolverMap.addSchemaResolver(httpSR); + } + + configure(); + super.init(); + } + + @SuppressWarnings("unchecked") + private T getInterceptorOfType(Class class1) { + for (Interceptor i : interceptors) + if (class1.isInstance(i)) + return (T) i; + return null; + } + + public String getWsdl() { + return wsdl; + } + + /** * @description The WSDL of the SOAP service. * @example http://predic8.de/my.wsdl or file:my.wsdl */ - @Required - @MCAttribute - public void setWsdl(String wsdl) { - this.wsdl = wsdl; - } - - public String getPortName() { - return portName; - } - - @MCAttribute - public void setPortName(String portName) { - this.portName = portName; - } - - public HttpClientConfiguration getWsdlHttpClientConfig() { - return httpClientConfig; - } - - @MCAttribute - public void setWsdlHttpClientConfig(HttpClientConfiguration httpClientConfig) { - this.httpClientConfig = httpClientConfig; - } - + @Required + @MCAttribute + public void setWsdl(String wsdl) { + this.wsdl = wsdl; + } + + public String getPortName() { + return portName; + } + + @MCAttribute + public void setPortName(String portName) { + this.portName = portName; + } + + public HttpClientConfiguration getWsdlHttpClientConfig() { + return httpClientConfig; + } + + @MCAttribute + public void setWsdlHttpClientConfig(HttpClientConfiguration httpClientConfig) { + this.httpClientConfig = httpClientConfig; + } + + public String getServiceName() { + return serviceName; + } + + @MCAttribute + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } } diff --git a/core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java b/core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java index 44140fcbdb..dc9e3d5283 100644 --- a/core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java +++ b/core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java @@ -14,30 +14,17 @@ package com.predic8.membrane.core.ws.relocator; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.annotation.concurrent.NotThreadSafe; -import javax.xml.namespace.QName; -import javax.xml.stream.XMLEventFactory; -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLEventWriter; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.Attribute; -import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; - -import com.predic8.membrane.core.Constants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.slf4j.*; + +import javax.annotation.concurrent.*; +import javax.xml.namespace.*; +import javax.xml.stream.*; +import javax.xml.stream.events.*; +import java.io.*; +import java.net.*; +import java.util.*; + +import static com.predic8.membrane.core.Constants.*; @NotThreadSafe public class Relocator { @@ -132,10 +119,8 @@ private XMLEvent getEvent(XMLEventReader parser) throws XMLStreamException { if (!event.isStartElement()) return event; - if (getElementName(event).getNamespaceURI().equals( - Constants.WSDL_SOAP11_NS) - || getElementName(event).getNamespaceURI().equals( - Constants.WSDL_SOAP12_NS)) { + if (getElementName(event).getNamespaceURI().equals(WSDL_SOAP11_NS) + || getElementName(event).getNamespaceURI().equals(WSDL_SOAP12_NS)) { wsdlFound = true; } diff --git a/core/src/test/java/com/predic8/membrane/core/UnitTests.java b/core/src/test/java/com/predic8/membrane/core/UnitTests.java index f1a11eea5e..573fa26259 100644 --- a/core/src/test/java/com/predic8/membrane/core/UnitTests.java +++ b/core/src/test/java/com/predic8/membrane/core/UnitTests.java @@ -13,90 +13,60 @@ limitations under the License. */ package com.predic8.membrane.core; -import com.predic8.membrane.core.config.CustomSpringConfigurationTest; import com.predic8.membrane.core.config.ProxyTest; -import com.predic8.membrane.core.config.ReadRulesConfigurationTest; -import com.predic8.membrane.core.config.ReadRulesWithInterceptorsConfigurationTest; -import com.predic8.membrane.core.exceptions.ProblemDetailsTest; -import com.predic8.membrane.core.exchangestore.AbortExchangeTest; -import com.predic8.membrane.core.exchangestore.AbstractExchangeStoreTest; -import com.predic8.membrane.core.exchangestore.LimitedMemoryExchangeStoreTest; -import com.predic8.membrane.core.graphql.GraphQLProtectionInterceptorTest; +import com.predic8.membrane.core.config.*; +import com.predic8.membrane.core.exceptions.*; +import com.predic8.membrane.core.exchangestore.*; +import com.predic8.membrane.core.graphql.*; import com.predic8.membrane.core.http.*; -import com.predic8.membrane.core.http.cookie.MessageBytesTest; +import com.predic8.membrane.core.http.cookie.*; import com.predic8.membrane.core.interceptor.*; -import com.predic8.membrane.core.interceptor.acl.AccessControlParserTest; -import com.predic8.membrane.core.interceptor.acl.HostnameTest; -import com.predic8.membrane.core.interceptor.acl.ParseTypeTest; -import com.predic8.membrane.core.interceptor.acl.matchers.Cidr.IpRangeTest; -import com.predic8.membrane.core.interceptor.apikey.ApiKeyUtils; -import com.predic8.membrane.core.interceptor.apikey.ApiKeysInterceptorTest; -import com.predic8.membrane.core.interceptor.apikey.extractors.ApiKeyHeaderExtractorTest; -import com.predic8.membrane.core.interceptor.apikey.stores.ApiKeyFileStoreTest; -import com.predic8.membrane.core.interceptor.authentication.BasicAuthenticationInterceptorTest; -import com.predic8.membrane.core.interceptor.authentication.session.StaticUserDataProviderTest; +import com.predic8.membrane.core.interceptor.acl.*; +import com.predic8.membrane.core.interceptor.acl.matchers.Cidr.*; +import com.predic8.membrane.core.interceptor.apikey.*; +import com.predic8.membrane.core.interceptor.apikey.extractors.*; +import com.predic8.membrane.core.interceptor.apikey.stores.*; +import com.predic8.membrane.core.interceptor.authentication.*; +import com.predic8.membrane.core.interceptor.authentication.session.*; import com.predic8.membrane.core.interceptor.balancer.*; -import com.predic8.membrane.core.interceptor.beautifier.BeautifierInterceptorTest; -import com.predic8.membrane.core.interceptor.cbr.XPathCBRInterceptorTest; -import com.predic8.membrane.core.interceptor.flow.ConditionalInterceptorGroovyTest; -import com.predic8.membrane.core.interceptor.flow.ConditionalInterceptorSpELTest; -import com.predic8.membrane.core.interceptor.formvalidation.FormValidationInterceptorTest; -import com.predic8.membrane.core.interceptor.groovy.GroovyInterceptorTest; -import com.predic8.membrane.core.interceptor.javascript.JavascriptInterceptor; -import com.predic8.membrane.core.interceptor.json.JsonPointerExtractorInterceptorTest; -import com.predic8.membrane.core.interceptor.json.JsonProtectionInterceptorTest; -import com.predic8.membrane.core.interceptor.json.ReplaceInterceptorTest; -import com.predic8.membrane.core.interceptor.log.AccessLogInterceptorTest; -import com.predic8.membrane.core.interceptor.misc.ReturnInterceptorTest; -import com.predic8.membrane.core.interceptor.misc.SetHeaderInterceptor; -import com.predic8.membrane.core.interceptor.misc.SetPropertyInterceptor; -import com.predic8.membrane.core.interceptor.oauth2.OAuth2UnitTests; -import com.predic8.membrane.core.interceptor.ratelimit.RateLimitInterceptorTest; -import com.predic8.membrane.core.interceptor.rest.HTTP2XMLInterceptorTest; -import com.predic8.membrane.core.interceptor.rewrite.ReverseProxyingInterceptorTest; -import com.predic8.membrane.core.interceptor.rewrite.RewriteInterceptorTest; -import com.predic8.membrane.core.interceptor.schemavalidation.JSONSchemaValidationTest; -import com.predic8.membrane.core.interceptor.schemavalidation.SOAPMessageValidatorInterceptorTest; -import com.predic8.membrane.core.interceptor.schemavalidation.SOAPUtilTest; -import com.predic8.membrane.core.interceptor.schemavalidation.ValidatorInterceptorTest; -import com.predic8.membrane.core.interceptor.security.PaddingHeaderInterceptorTest; -import com.predic8.membrane.core.interceptor.soap.SoapOperationExtractorTest; -import com.predic8.membrane.core.interceptor.templating.TemplateInterceptorTest; -import com.predic8.membrane.core.interceptor.xml.Json2XmlInterceptorTest; -import com.predic8.membrane.core.interceptor.xml.Xml2JsonInterceptorTest; -import com.predic8.membrane.core.interceptor.xml.XmlPathExtractorInterceptorTest; -import com.predic8.membrane.core.interceptor.xmlcontentfilter.SimpleXPathAnalyzerTest; -import com.predic8.membrane.core.interceptor.xmlcontentfilter.SimpleXPathParserTest; -import com.predic8.membrane.core.interceptor.xmlcontentfilter.XMLContentFilterTest; -import com.predic8.membrane.core.interceptor.xmlcontentfilter.XMLElementFinderTest; -import com.predic8.membrane.core.interceptor.xmlprotection.XMLProtectorTest; -import com.predic8.membrane.core.interceptor.xslt.XSLTInterceptorTest; -import com.predic8.membrane.core.kubernetes.client.KubernetesClientTest; -import com.predic8.membrane.core.lang.spel.ExchangeEvaluationContextTest; -import com.predic8.membrane.core.lang.spel.functions.BuiltInFunctionsTest; -import com.predic8.membrane.core.lang.spel.functions.ReflectiveMethodHandlerTest; -import com.predic8.membrane.core.magic.MagicTest; -import com.predic8.membrane.core.multipart.ReassembleTest; -import com.predic8.membrane.core.resolver.SingleResolverTest; -import com.predic8.membrane.core.rules.APIProxyKeyTest; -import com.predic8.membrane.core.rules.ProxyRuleTest; -import com.predic8.membrane.core.rules.ServiceProxyKeyTest; -import com.predic8.membrane.core.transport.ExchangeTest; -import com.predic8.membrane.core.transport.http.HostColonPortTest; -import com.predic8.membrane.core.transport.http.HttpKeepAliveTest; -import com.predic8.membrane.core.transport.http.ServiceInvocationTest; -import com.predic8.membrane.core.transport.http2.Http2ClientServerTest; -import com.predic8.membrane.core.transport.ssl.SSLContextTest; -import com.predic8.membrane.core.transport.ssl.SessionResumptionTest; -import com.predic8.membrane.core.transport.ssl.acme.AcmeRenewTest; -import com.predic8.membrane.core.transport.ssl.acme.AcmeStepTest; +import com.predic8.membrane.core.interceptor.beautifier.*; +import com.predic8.membrane.core.interceptor.cbr.*; +import com.predic8.membrane.core.interceptor.flow.*; +import com.predic8.membrane.core.interceptor.formvalidation.*; +import com.predic8.membrane.core.interceptor.groovy.*; +import com.predic8.membrane.core.interceptor.javascript.*; +import com.predic8.membrane.core.interceptor.json.*; +import com.predic8.membrane.core.interceptor.log.*; +import com.predic8.membrane.core.interceptor.misc.*; +import com.predic8.membrane.core.interceptor.oauth2.*; +import com.predic8.membrane.core.interceptor.ratelimit.*; +import com.predic8.membrane.core.interceptor.rest.*; +import com.predic8.membrane.core.interceptor.rewrite.*; +import com.predic8.membrane.core.interceptor.schemavalidation.*; +import com.predic8.membrane.core.interceptor.security.*; +import com.predic8.membrane.core.interceptor.soap.*; +import com.predic8.membrane.core.interceptor.templating.*; +import com.predic8.membrane.core.interceptor.xml.*; +import com.predic8.membrane.core.interceptor.xmlcontentfilter.*; +import com.predic8.membrane.core.interceptor.xmlprotection.*; +import com.predic8.membrane.core.interceptor.xslt.*; +import com.predic8.membrane.core.kubernetes.client.*; +import com.predic8.membrane.core.lang.spel.*; +import com.predic8.membrane.core.lang.spel.functions.*; +import com.predic8.membrane.core.magic.*; +import com.predic8.membrane.core.multipart.*; +import com.predic8.membrane.core.resolver.*; +import com.predic8.membrane.core.rules.*; +import com.predic8.membrane.core.transport.*; +import com.predic8.membrane.core.transport.http.*; +import com.predic8.membrane.core.transport.http2.*; +import com.predic8.membrane.core.transport.ssl.*; +import com.predic8.membrane.core.transport.ssl.acme.*; import com.predic8.membrane.core.util.*; -import com.predic8.membrane.core.ws.relocator.RelocatorTest; -import com.predic8.membrane.core.ws.relocator.RelocatorWADLTest; -import com.predic8.membrane.interceptor.MultipleLoadBalancersTest; -import org.junit.platform.suite.api.SelectClasses; -import org.junit.platform.suite.api.SelectPackages; -import org.junit.platform.suite.api.Suite; +import com.predic8.membrane.core.ws.*; +import com.predic8.membrane.core.ws.relocator.*; +import com.predic8.membrane.interceptor.*; +import org.junit.platform.suite.api.*; @Suite @SelectClasses({HeaderTest.class, BodyTest.class, ByteUtilTest.class, @@ -132,6 +102,8 @@ SimpleXPathAnalyzerTest.class, SimpleXPathParserTest.class, InternalInvocationTest.class, HeaderFilterInterceptorTest.class, SOAPUtilTest.class, SoapOperationExtractorTest.class, + SoapProxyInvocationTest.class, // @TODO Check Proper naming! + SOAPProxyTest.class, ContentTypeDetectorTest.class, MessageAnalyserTest.class, ExchangeTest.class, LimitedMemoryExchangeStoreTest.class, diff --git a/core/src/test/java/com/predic8/membrane/core/interceptor/WSDLInterceptorTest.java b/core/src/test/java/com/predic8/membrane/core/interceptor/WSDLInterceptorTest.java index b7449a002f..9dc406a30d 100644 --- a/core/src/test/java/com/predic8/membrane/core/interceptor/WSDLInterceptorTest.java +++ b/core/src/test/java/com/predic8/membrane/core/interceptor/WSDLInterceptorTest.java @@ -13,42 +13,25 @@ limitations under the License. */ package com.predic8.membrane.core.interceptor; -import static com.predic8.membrane.core.Constants.WSDL_HTTP_NS; -import static com.predic8.membrane.core.Constants.WSDL_SOAP11_NS; -import static com.predic8.membrane.core.Constants.WSDL_SOAP12_NS; +import com.predic8.membrane.core.exchange.*; +import com.predic8.membrane.core.transport.http.*; +import com.predic8.membrane.core.util.*; +import org.junit.jupiter.api.*; + +import javax.xml.*; +import javax.xml.namespace.*; +import javax.xml.stream.*; +import javax.xml.stream.events.*; +import java.io.*; +import java.util.regex.*; + +import static com.predic8.membrane.core.Constants.*; +import static com.predic8.membrane.core.http.Response.*; +import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE; import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.*; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.regex.Pattern; - -import javax.xml.XMLConstants; -import javax.xml.namespace.QName; -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import com.predic8.membrane.core.exchange.Exchange; -import com.predic8.membrane.core.http.Response; -import com.predic8.membrane.core.transport.http.FakeHttpHandler; -import com.predic8.membrane.core.util.MessageUtil; public class WSDLInterceptorTest { - private static final QName ADDRESS_SOAP11 = new QName(WSDL_SOAP11_NS, - "address"); - private static final QName ADDRESS_SOAP12 = new QName(WSDL_SOAP12_NS, - "address"); - private static final QName ADDRESS_HTTP = new QName(WSDL_HTTP_NS, "address"); - private Exchange exc; private WSDLInterceptor interceptor; @@ -58,53 +41,56 @@ public void setUp() throws Exception { exc = new Exchange(new FakeHttpHandler(3011)); exc.setRequest(MessageUtil .getGetRequest("/axis2/services/BLZService?wsdl")); - InputStream resourceAsStream = WSDLInterceptorTest.class.getResourceAsStream("/blz-service.wsdl"); - Response okResponse = Response.ok() + exc.setResponse(ok() .contentType("text/xml; charset=utf-8") - .body(resourceAsStream, true) - .build(); - exc.setResponse(okResponse); + .body(WSDLInterceptorTest.class.getResourceAsStream("/blz-service.wsdl"), true) + .build()); exc.setOriginalHostHeader("thomas-bayer.com:80"); interceptor = new WSDLInterceptor(); } + /** + * Tests rewrite from: + * + * To: + * + * + */ @Test public void testProtocolSet() throws Exception { interceptor.setProtocol("https"); - assertEquals(interceptor.handleResponse(exc), Outcome.CONTINUE); + assertEquals(interceptor.handleResponse(exc), CONTINUE); XMLEventReader parser = getParser(); - // System.out.println("parser is: " + parser); - - StartElement element = getElement(parser, ADDRESS_SOAP11); + StartElement element = getElement(parser, WSDL11_ADDRESS_SOAP11); String locationAttr = getLocationAttributeFor(element); - // System.out.println("location attribute is: " + locationAttr); + assertTrue(locationAttr.startsWith("https://")); assertTrue(getLocationAttributeFor( - getElement(getParser(), ADDRESS_SOAP12)).startsWith("https://")); + getElement(getParser(), WSDL11_ADDRESS_SOAP12)).startsWith("https://")); assertTrue(getLocationAttributeFor( - getElement(getParser(), ADDRESS_HTTP)).startsWith("https://")); + getElement(getParser(), WSDL11_ADDRESS_HTTP)).startsWith("https://")); } @Test public void testProtocolDefault() throws Exception { - assertEquals(interceptor.handleResponse(exc), Outcome.CONTINUE); + assertEquals(interceptor.handleResponse(exc), CONTINUE); assertTrue(getLocationAttributeFor( - getElement(getParser(), ADDRESS_SOAP11)).startsWith("http://")); + getElement(getParser(), WSDL11_ADDRESS_SOAP11)).startsWith("http://")); assertTrue(getLocationAttributeFor( - getElement(getParser(), ADDRESS_SOAP12)).startsWith("http://")); + getElement(getParser(), WSDL11_ADDRESS_SOAP12)).startsWith("http://")); assertTrue(getLocationAttributeFor( - getElement(getParser(), ADDRESS_HTTP)).startsWith("http://")); + getElement(getParser(), WSDL11_ADDRESS_HTTP)).startsWith("http://")); } @Test public void testPortEmpty() throws Exception { interceptor.setPort(""); - assertEquals(interceptor.handleResponse(exc), Outcome.CONTINUE); + assertEquals(interceptor.handleResponse(exc), CONTINUE); assertFalse(matchSoap11(".*:80.*")); assertFalse(matchSoap12(".*:80.*")); assertFalse(matchHttp(".*:80.*")); @@ -112,7 +98,7 @@ public void testPortEmpty() throws Exception { @Test public void testPortDefault() throws Exception { - assertEquals(interceptor.handleResponse(exc), Outcome.CONTINUE); + assertEquals(interceptor.handleResponse(exc), CONTINUE); assertTrue(matchSoap11(".*:3011.*")); assertTrue(matchSoap12(".*:3011.*")); assertTrue(matchHttp(".*:3011.*")); @@ -121,7 +107,7 @@ public void testPortDefault() throws Exception { @Test public void testPortSet() throws Exception { interceptor.setPort("2000"); - assertEquals(interceptor.handleResponse(exc), Outcome.CONTINUE); + assertEquals(interceptor.handleResponse(exc), CONTINUE); assertTrue(matchSoap11(".*:2000.*")); assertTrue(matchSoap12(".*:2000.*")); assertTrue(matchHttp(".*:2000.*")); @@ -130,8 +116,7 @@ public void testPortSet() throws Exception { @Test public void testHostSet() throws Exception { interceptor.setHost("abc.com"); - assertEquals(interceptor.handleResponse(exc), Outcome.CONTINUE); - + assertEquals(interceptor.handleResponse(exc), CONTINUE); assertTrue(matchSoap11("http://abc.com.*")); assertTrue(matchSoap12("http://abc.com.*")); assertTrue(matchHttp("http://abc.com.*")); @@ -139,8 +124,7 @@ public void testHostSet() throws Exception { @Test public void testHostDefault() throws Exception { - assertEquals(interceptor.handleResponse(exc), Outcome.CONTINUE); - + assertEquals(interceptor.handleResponse(exc), CONTINUE); assertTrue(matchSoap11("http://thomas-bayer.com.*")); assertTrue(matchSoap12("http://thomas-bayer.com.*")); assertTrue(matchHttp("http://thomas-bayer.com.*")); @@ -159,17 +143,17 @@ private String getLocationAttributeFor(StartElement element) { private boolean matchSoap12(String pattern) throws XMLStreamException, Exception { - return match(pattern, ADDRESS_SOAP12); + return match(pattern, WSDL11_ADDRESS_SOAP12); } private boolean matchSoap11(String pattern) throws XMLStreamException, Exception { - return match(pattern, ADDRESS_SOAP11); + return match(pattern, WSDL11_ADDRESS_SOAP11); } private boolean matchHttp(String pattern) throws XMLStreamException, Exception { - return match(pattern, ADDRESS_HTTP); + return match(pattern, WSDL11_ADDRESS_HTTP); } private boolean match(String pattern, QName addressElementName) diff --git a/core/src/test/java/com/predic8/membrane/core/rules/SOAPProxyTest.java b/core/src/test/java/com/predic8/membrane/core/rules/SOAPProxyTest.java new file mode 100644 index 0000000000..c827a693bd --- /dev/null +++ b/core/src/test/java/com/predic8/membrane/core/rules/SOAPProxyTest.java @@ -0,0 +1,50 @@ +package com.predic8.membrane.core.rules; + +import com.predic8.membrane.core.*; +import com.predic8.membrane.core.exchangestore.*; +import com.predic8.membrane.core.transport.http.*; +import org.junit.jupiter.api.*; + +public class SOAPProxyTest { + + Router router; + + SOAPProxy proxy; + + @BeforeEach + void setUp() throws Exception { + + proxy = new SOAPProxy(); + router = new Router(); + router.setTransport(new HttpTransport()); + router.setExchangeStore(new ForgetfulExchangeStore()); + router.add(proxy); + } + + @Test + void parseWSDL() throws Exception { + proxy.setWsdl("classpath:/ws/cities.wsdl"); + router.init(); + } + + @Test + void parseWSDLWithMultiplePortsPerService() throws Exception { + proxy.setWsdl("classpath:/blz-service.wsdl"); + router.init(); + } + + @Test + void parseWSDLWithMultipleServices() { + proxy.setWsdl("classpath:/ws/cities-2-services.wsdl"); + Assertions.assertThrows(IllegalArgumentException.class, () -> router.init()); + } + + @Test + void parseWSDLWithMultipleServicesForAGivenService() throws Exception { + proxy.setServiceName("CityServiceA"); + proxy.setWsdl("classpath:/ws/cities-2-services.wsdl"); + router.init(); + } + + +} \ No newline at end of file diff --git a/core/src/test/java/com/predic8/membrane/core/ws/SoapProxyInvocationTest.java b/core/src/test/java/com/predic8/membrane/core/ws/SoapProxyInvocationTest.java new file mode 100644 index 0000000000..bbd579cd03 --- /dev/null +++ b/core/src/test/java/com/predic8/membrane/core/ws/SoapProxyInvocationTest.java @@ -0,0 +1,82 @@ +package com.predic8.membrane.core.ws; + +import com.predic8.membrane.core.*; +import com.predic8.membrane.core.exchange.*; +import com.predic8.membrane.core.interceptor.*; +import com.predic8.membrane.core.interceptor.soap.*; +import com.predic8.membrane.core.openapi.serviceproxy.*; +import com.predic8.membrane.core.openapi.util.*; +import com.predic8.membrane.core.rules.*; +import io.restassured.response.*; +import org.junit.jupiter.api.*; + +import static com.predic8.membrane.core.http.MimeType.*; +import static io.restassured.RestAssured.*; +import static org.hamcrest.Matchers.*; + +public class SoapProxyInvocationTest { + + static Router gw; + static Router n1; + + static Exchange last; + + @BeforeAll + public static void setup() throws Exception { + + + n1 = new HttpRouter(); + APIProxy api = new APIProxy(); + api.setPort(2001); + api.getInterceptors().add(new SampleSoapServiceInterceptor()); + n1.getRuleManager().addProxyAndOpenPortIfNew(api); + n1.init(); + + gw = new HttpRouter(); + gw.setHotDeploy(false); + SOAPProxy soapProxy = new SOAPProxy(); + soapProxy.setPort(2000); + soapProxy.setWsdl("classpath:/ws/cities.wsdl"); + soapProxy.getInterceptors().add(new AbstractInterceptor() { + @Override + public Outcome handleRequest(Exchange exc) throws Exception { + System.out.println("exc.getDestinations() = " + exc.getDestinations()); + last = exc; + return Outcome.CONTINUE; + } + }); + + gw.getRuleManager().addProxyAndOpenPortIfNew(soapProxy); + gw.init(); + } + + @Test + void WSDLRewriting() throws Exception { + // @formatter:off + given() + .get("http://localhost:2000/?wsdl") + .then() + .statusCode(200) + .contentType(TEXT_XML) + .body("definitions.service.port.address.@location", equalTo("http://localhost:2000/")); + // @formatter:on + } + + @Test + void callService() { + // @formatter:off + ResponseBody body = given().when().body(TestUtils.getResourceAsStream(this,"/soap-sample/soap-request-bonn.xml")) + .post("http://localhost:2000/services/cities").then() + + + .statusCode(200) + .contentType(TEXT_XML) + .body("Envelope.Body.getCityResponse.country", equalTo("Germany")) + .extract().response().body(); + + System.out.println("body.prettyPrint() = " + body.prettyPrint()); + + System.out.println("last.getDestinations() = " + last.getDestinations()); // @TODO assert + + } +} diff --git a/core/src/test/java/com/predic8/membrane/core/ws/relocator/RelocatorTest.java b/core/src/test/java/com/predic8/membrane/core/ws/relocator/RelocatorTest.java index 836dccd769..a49f9fc1e5 100644 --- a/core/src/test/java/com/predic8/membrane/core/ws/relocator/RelocatorTest.java +++ b/core/src/test/java/com/predic8/membrane/core/ws/relocator/RelocatorTest.java @@ -14,6 +14,7 @@ package com.predic8.membrane.core.ws.relocator; import com.predic8.membrane.core.util.*; +import org.apache.commons.io.output.ByteArrayOutputStream; import org.jetbrains.annotations.*; import org.junit.jupiter.api.*; @@ -21,33 +22,30 @@ import static java.nio.charset.StandardCharsets.*; import static java.util.Objects.*; -import static org.apache.commons.io.output.NullOutputStream.*; import static org.junit.jupiter.api.Assertions.*; public class RelocatorTest { private static Relocator relocator; + ByteArrayOutputStream os; @BeforeEach public void setUp() throws Exception { + + os = new ByteArrayOutputStream(); + relocator = new Relocator(new OutputStreamWriter( - NULL_OUTPUT_STREAM, UTF_8), "http", "localhost", + os, UTF_8), "http", "localhost", 3000, "", null); } @Test public void testWSDLRelocate() throws Exception { relocator.relocate(getFile("/blz-service.wsdl")); - System.out.println("relocator.isWsdlFound() = " + relocator.isWsdlFound()); - } - - @NotNull - private InputStreamReader getFile(String filename) throws IOException { - return new InputStreamReader(new ByteArrayInputStream( - getFileAsBytes(filename)), UTF_8); + assertTrue(relocator.isWsdlFound()); + System.out.println("os.toString(UTF_8) = " + os.toString(UTF_8)); } - @Test public void testXMLRelocate() throws Exception { relocator.relocate(getFile("/acl/acl.xml")); @@ -59,4 +57,10 @@ private byte[] getFileAsBytes(String name) throws IOException { return ByteUtil.getByteArrayData(requireNonNull(this.getClass() .getResourceAsStream(name))); } + + @NotNull + private InputStreamReader getFile(String filename) throws IOException { + return new InputStreamReader(new ByteArrayInputStream( + getFileAsBytes(filename)), UTF_8); + } } diff --git a/core/src/test/resources/ws/cities-2-services.wsdl b/core/src/test/resources/ws/cities-2-services.wsdl new file mode 100644 index 0000000000..662a05bd31 --- /dev/null +++ b/core/src/test/resources/ws/cities-2-services.wsdl @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/src/test/resources/ws/cities.wsdl b/core/src/test/resources/ws/cities.wsdl new file mode 100644 index 0000000000..c8da9e8e29 --- /dev/null +++ b/core/src/test/resources/ws/cities.wsdl @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file