Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,8 @@
import com.predic8.membrane.annot.*;
import com.predic8.membrane.core.config.*;
import com.predic8.membrane.core.config.security.*;
import com.predic8.membrane.core.config.xml.*;
import com.predic8.membrane.core.exchange.*;
import com.predic8.membrane.core.interceptor.*;
import com.predic8.membrane.core.lang.*;
import com.predic8.membrane.core.lang.ExchangeExpression.*;
import com.predic8.membrane.core.router.*;
import com.predic8.membrane.core.transport.ssl.*;

import static com.predic8.membrane.core.lang.ExchangeExpression.Language.*;

public abstract class AbstractServiceProxy extends SSLableProxy {

@Override
Expand Down Expand Up @@ -89,167 +81,6 @@ public void setPath(Path path) {
}
}

/**
* @description <p>
* The destination where the service proxy will send messages to.
* Use the target element if you want to send the messages to a target.
* Supports dynamic destinations through expressions.
* </p>
*/
@MCElement(name = "target", component = false)
public static class Target implements XMLSupport {
private String host;
private int port = -1;
private String method;
protected String url;
private boolean adjustHostHeader = true;
private ExchangeExpression.Language language = SPEL;
private ExchangeExpression exchangeExpression;

private SSLParser sslParser;

protected XmlConfig xmlConfig;

public void init(Router router) {
if (url != null) {
exchangeExpression = TemplateExchangeExpression.newInstance(new InterceptorAdapter(router, xmlConfig), language, url);
}

}

public String compileUrl(Exchange exc, Interceptor.Flow flow) {
/*
* Will always evaluate on every call. This is fine as SpEL is fast enough and performs its own optimizations.
* 1.000.000 calls ~10ms
*/
if (exchangeExpression != null) {
return exchangeExpression.evaluate(exc, flow, String.class);
}
return url;
}

public Target() {
}

public Target(String host) {
setHost(host);
}

public Target(String host, int port) {
setHost(host);
setPort(port);
}

public String getHost() {
return host;
}

/**
* @description Host address of the target.
* @example localhost, 192.168.1.1
*/
@MCAttribute
public void setHost(String host) {
this.host = host;
}

public int getPort() {
return port;
}

/**
* @description Port number of the target.
* @default 80
* @example 8080
*/
@MCAttribute
public void setPort(int port) {
this.port = port;
}

public String getUrl() {
return url;
}

/**
* @description Absolute URL of the target. If this is set, <i>host</i> and <i>port</i> will be ignored.
* Supports inline expressions through <code>${&lt;expression&gt;}</code> elements.
* @example <a href="http://membrane-soa.org">http://membrane-soa.org</a>
*/
@MCAttribute
public void setUrl(String url) {
this.url = url;
}

public SSLParser getSslParser() {
return sslParser;
}

/**
* @description Configures outbound SSL (HTTPS).
*/
@MCChildElement(allowForeign = true)
public void setSslParser(SSLParser sslParser) {
this.sslParser = sslParser;
}

public boolean isAdjustHostHeader() {
return adjustHostHeader;
}

@MCAttribute
public void setAdjustHostHeader(boolean adjustHostHeader) {
this.adjustHostHeader = adjustHostHeader;
}

public String getMethod() {
return method;
}

/**
* @description The method that should be used to make the call to the backend.
* Overwrites the original method.
* @param method
*/
@MCAttribute
public void setMethod(String method) {
this.method = method;
}

public ExchangeExpression getExchangeExpression() {
return exchangeExpression;
}

public ExchangeExpression.Language getLanguage() {
return language;
}

/**
* @description the language of the inline expressions
* @default SpEL
* @example SpEL, groovy, jsonpath, xpath
*/
@MCAttribute
public void setLanguage(ExchangeExpression.Language language) {
this.language = language;
}

/**
* XML Configuration e.g. declaration of XML namespaces for XPath expressions, ...
* @param xmlConfig
*/
@Override
@MCChildElement(allowForeign = true,order = 10)
public void setXmlConfig(XmlConfig xmlConfig) {
this.xmlConfig = xmlConfig;
}

@Override
public XmlConfig getXmlConfig() {
return xmlConfig;
}
}

protected Target target = new Target();

public Target getTarget() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,25 +121,32 @@ public synchronized void openPorts() throws IOException {
}

private @NotNull HashMap<IpPort, SSLContextCollection.Builder> getSSLContexts() throws UnknownHostException {
HashMap<IpPort, SSLContextCollection.Builder> sslContexts = new HashMap<>();
HashMap<IpPort, SSLContextCollection.Builder> sslContextBuilders = new HashMap<>();
for (Proxy proxy : proxies) {
if (!(proxy instanceof SSLableProxy sp))
continue;

SSLContext sslContext = sp.getSslInboundContext();
if (sslContext == null)
continue;

IpPort ipPort = getIpPort(sp);
SSLContextCollection.Builder builder = sslContexts.get(ipPort);
if (builder == null) {
builder = new SSLContextCollection.Builder();
sslContexts.put(ipPort, builder);
switch (proxy) {
case SSLProxy sslp:
getOrCreateBuilder(sslp, sslContextBuilders).useCollection();
break;
case SSLableProxy sslap:
SSLContext sslContext = sslap.getSslInboundContext();
if (sslContext == null)
continue;
getOrCreateBuilder(sslap, sslContextBuilders).add(sslContext);
break;
default: break;
}
builder.add(sslContext);
}
return sslContextBuilders;
}

private static SSLContextCollection.@NotNull Builder getOrCreateBuilder(Proxy proxy, HashMap<IpPort, SSLContextCollection.Builder> sslContexts) throws UnknownHostException {
IpPort ipPort = getIpPort(proxy);
SSLContextCollection.Builder builder = sslContexts.get(ipPort);
if (builder == null) {
builder = new SSLContextCollection.Builder();
sslContexts.put(ipPort, builder);
}
return sslContexts;
return builder;
}


Expand Down
76 changes: 33 additions & 43 deletions core/src/main/java/com/predic8/membrane/core/proxies/SSLProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,49 @@
package com.predic8.membrane.core.proxies;

import com.google.common.base.Objects;
import com.predic8.membrane.annot.MCAttribute;
import com.predic8.membrane.annot.MCChildElement;
import com.predic8.membrane.annot.MCElement;
import com.predic8.membrane.core.config.security.SSLParser;
import com.predic8.membrane.core.exchange.Exchange;
import com.predic8.membrane.annot.*;
import com.predic8.membrane.core.config.security.*;
import com.predic8.membrane.core.exchange.*;
import com.predic8.membrane.core.interceptor.*;
import com.predic8.membrane.core.router.*;
import com.predic8.membrane.core.sslinterceptor.SSLInterceptor;
import com.predic8.membrane.core.stats.RuleStatisticCollector;
import com.predic8.membrane.core.sslinterceptor.*;
import com.predic8.membrane.core.stats.*;
import com.predic8.membrane.core.transport.http.*;
import com.predic8.membrane.core.transport.http.client.ConnectionConfiguration;
import com.predic8.membrane.core.transport.http.client.*;
import com.predic8.membrane.core.transport.http.streampump.*;
import com.predic8.membrane.core.transport.ssl.SSLContext;
import com.predic8.membrane.core.transport.ssl.SSLExchange;
import com.predic8.membrane.core.transport.ssl.SSLProvider;
import com.predic8.membrane.core.transport.ssl.StaticSSLContext;
import com.predic8.membrane.core.util.DNSCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.predic8.membrane.annot.Required;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

import static com.predic8.membrane.core.interceptor.FlowController.ABORTION_REASON;
import com.predic8.membrane.core.transport.ssl.*;
import com.predic8.membrane.core.util.*;
import org.slf4j.*;

import java.io.*;
import java.net.*;
import java.util.*;

import static com.predic8.membrane.core.interceptor.FlowController.*;

/**
* Proxies SSL connections to a target server without decrypting the traffic.
*/
@MCElement(name="sslProxy")
@MCElement(name = "sslProxy", topLevel = true, component = false)
public class SSLProxy implements Proxy {
private static final Logger log = LoggerFactory.getLogger(SSLProxy.class.getName());

private Target target;
private SSLProxy.Target target;
private ConnectionConfiguration connectionConfiguration = new ConnectionConfiguration();
private final RuleStatisticCollector ruleStatisticCollector = new RuleStatisticCollector();
private boolean useAsDefault = true;
private List<SSLInterceptor> sslInterceptors = new ArrayList<>();

@MCElement(id = "sslProxy-target", name="target", component = false)
public ConnectionConfiguration getConnectionConfiguration() {
return connectionConfiguration;
}

@MCChildElement(order = 0)
public void setConnectionConfiguration(ConnectionConfiguration connectionConfiguration) {
this.connectionConfiguration = connectionConfiguration;
}

@MCElement(id = "sslProxy-target", name = "target", component = false)
public static class Target {
private int port = -1;
private String host;
Expand All @@ -82,22 +81,13 @@ public void setHost(String host) {
}
}

public ConnectionConfiguration getConnectionConfiguration() {
return connectionConfiguration;
}

@MCChildElement(order = 0)
public void setConnectionConfiguration(ConnectionConfiguration connectionConfiguration) {
this.connectionConfiguration = connectionConfiguration;
}

public Target getTarget() {
public SSLProxy.Target getTarget() {
return target;
}

@Required
@MCChildElement(order = 100)
public void setTarget(Target target) {
public void setTarget(SSLProxy.Target target) {
this.target = target;
}

Expand All @@ -115,7 +105,7 @@ public List<SSLInterceptor> getSslInterceptors() {
return sslInterceptors;
}

@MCChildElement(allowForeign=true, order=50)
@MCChildElement(allowForeign = true, order = 50)
public void setSslInterceptors(List<SSLInterceptor> sslInterceptors) {
this.sslInterceptors = sslInterceptors;
}
Expand Down Expand Up @@ -174,7 +164,7 @@ public void setName(String name) {

@Override
public String getName() {
return "SSL " + getHost() + ":" + getPort();
return "SSL %s:%d".formatted(getHost(), getPort());
}

@Override
Expand Down Expand Up @@ -361,8 +351,8 @@ public Socket wrap(Socket socket, byte[] buffer, int position) throws IOExceptio
log.error("", (Throwable) exc.getProperty(ABORTION_REASON));
byte error = exc.getError().getCode();

byte[] alert_unrecognized_name = { 21 /* alert */, 3, 1 /* TLS 1.0 */, 0, 2 /* length: 2 bytes */,
2 /* fatal */, error };
byte[] alert_unrecognized_name = {21 /* alert */, 3, 1 /* TLS 1.0 */, 0, 2 /* length: 2 bytes */,
2 /* fatal */, error};

try (socket) {
socket.getOutputStream().write(alert_unrecognized_name);
Expand Down
Loading
Loading