This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new 52bad9af3a JAMES-3788 Allow configuring if Proxy or SSL frames should
be handled… (#2634)
52bad9af3a is described below
commit 52bad9af3add74332d583632ccc5bca3727c1474
Author: Benoit TELLIER <[email protected]>
AuthorDate: Tue Feb 11 08:43:08 2025 +0100
JAMES-3788 Allow configuring if Proxy or SSL frames should be handled…
(#2634)
- SSL aware load balancer with an SSL backend would generally establish
SSL termination first then handover proxy information, for example secure
setup in a third party data center.
- Simpler setup in just TCP transparent and (eg HAProxy in TCP mode) and
would
only append the proxy frames prior to the SSL handshake.
We need a mode to distinguish both setups.
---
docs/modules/servers/partials/configure/imap.adoc | 5 +++++
docs/modules/servers/partials/configure/smtp.adoc | 5 +++++
.../netty/AbstractSSLAwareChannelPipelineFactory.java | 12 +++++++-----
.../java/org/apache/james/protocols/netty/NettyServer.java | 2 ++
.../java/org/apache/james/imapserver/netty/IMAPServer.java | 2 +-
.../protocols/lib/netty/AbstractConfigurableAsyncServer.java | 5 ++++-
src/site/xdoc/server/config-imap4.xml | 7 ++++++-
src/site/xdoc/server/config-smtp-lmtp.xml | 5 +++++
8 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/docs/modules/servers/partials/configure/imap.adoc
b/docs/modules/servers/partials/configure/imap.adoc
index 0fe943cb8a..b6df670256 100644
--- a/docs/modules/servers/partials/configure/imap.adoc
+++ b/docs/modules/servers/partials/configure/imap.adoc
@@ -118,6 +118,11 @@ Integer, defaults to 4096, must be positive, 0 means no
queue.
with other proxies (e.g. traefik). If enabled, it is *required* to initiate
the connection
using HAProxy's proxy protocol.
+| proxyFirst
+| Whether proxy frames should be handled before SSL handshakes. This allows
setting either the loadbalancer in TCP mode
+(so transparent for SSL then Proxy frames needs to be handled first) or set up
SSL termination between proxy and server
+(more suited for some cloud vendors). Defaults to true (TCP transparent).
+
| bossWorkerCount
| Set the maximum count of boss threads. Boss threads are responsible for
accepting incoming IMAP connections
and initializing associated resources. Optional integer, by default, boss
threads are not used and this responsibility is being dealt with
diff --git a/docs/modules/servers/partials/configure/smtp.adoc
b/docs/modules/servers/partials/configure/smtp.adoc
index d2d8d519c4..1a68a0094f 100644
--- a/docs/modules/servers/partials/configure/smtp.adoc
+++ b/docs/modules/servers/partials/configure/smtp.adoc
@@ -57,6 +57,11 @@ this case, if nobody is present, the value "localhost" will
be used.
with other proxies (e.g. traefik). If enabled, it is *required* to initiate
the connection
using HAProxy's proxy protocol.
+| proxyFirst
+| Whether proxy frames should be handled before SSL handshakes. This allows
setting either the loadbalancer in TCP mode
+(so transparent for SSL then Proxy frames needs to be handled first) or set up
SSL termination between proxy and server
+(more suited for some cloud vendors). Defaults to true (TCP transparent).
+
| authRequired
| (deprecated) use auth.announce instead.
diff --git
a/protocols/netty/src/main/java/org/apache/james/protocols/netty/AbstractSSLAwareChannelPipelineFactory.java
b/protocols/netty/src/main/java/org/apache/james/protocols/netty/AbstractSSLAwareChannelPipelineFactory.java
index 7fe9804fdb..0b1c340280 100644
---
a/protocols/netty/src/main/java/org/apache/james/protocols/netty/AbstractSSLAwareChannelPipelineFactory.java
+++
b/protocols/netty/src/main/java/org/apache/james/protocols/netty/AbstractSSLAwareChannelPipelineFactory.java
@@ -32,21 +32,23 @@ import io.netty.util.concurrent.EventExecutorGroup;
@ChannelHandler.Sharable
public abstract class AbstractSSLAwareChannelPipelineFactory<C extends
SocketChannel> extends AbstractChannelPipelineFactory<C> {
private final boolean proxyRequired;
+ private final boolean proxyFirst;
private Supplier<Encryption> secure;
public AbstractSSLAwareChannelPipelineFactory(int timeout,
int maxConnections, int
maxConnectsPerIp,
- boolean proxyRequired,
+ boolean proxyRequired,
boolean proxyFirst,
ChannelHandlerFactory
frameHandlerFactory,
EventExecutorGroup
eventExecutorGroup) {
super(timeout, maxConnections, maxConnectsPerIp, proxyRequired,
frameHandlerFactory, eventExecutorGroup);
this.proxyRequired = proxyRequired;
+ this.proxyFirst = proxyFirst;
}
public AbstractSSLAwareChannelPipelineFactory(int timeout,
- int maxConnections, int maxConnectsPerIp, boolean proxyRequired,
Supplier<Encryption> secure,
- ChannelHandlerFactory frameHandlerFactory, EventExecutorGroup
eventExecutorGroup) {
- this(timeout, maxConnections, maxConnectsPerIp, proxyRequired,
frameHandlerFactory, eventExecutorGroup);
+ int maxConnections, int
maxConnectsPerIp, boolean proxyRequired, boolean proxyFirst,
Supplier<Encryption> secure,
+ ChannelHandlerFactory
frameHandlerFactory, EventExecutorGroup eventExecutorGroup) {
+ this(timeout, maxConnections, maxConnectsPerIp, proxyRequired,
proxyFirst, frameHandlerFactory, eventExecutorGroup);
this.secure = secure;
}
@@ -56,7 +58,7 @@ public abstract class
AbstractSSLAwareChannelPipelineFactory<C extends SocketCha
super.initChannel(channel);
if (isSSLSocket()) {
- if (proxyRequired) {
+ if (proxyRequired && proxyFirst) {
channel.pipeline().addAfter(HandlerConstants.PROXY_HANDLER,
HandlerConstants.SSL_HANDLER, secure.get().sslHandler());
} else {
channel.pipeline().addFirst(HandlerConstants.SSL_HANDLER,
secure.get().sslHandler());
diff --git
a/protocols/netty/src/main/java/org/apache/james/protocols/netty/NettyServer.java
b/protocols/netty/src/main/java/org/apache/james/protocols/netty/NettyServer.java
index bd7a7d62d8..7e69363d84 100644
---
a/protocols/netty/src/main/java/org/apache/james/protocols/netty/NettyServer.java
+++
b/protocols/netty/src/main/java/org/apache/james/protocols/netty/NettyServer.java
@@ -123,11 +123,13 @@ public class NettyServer extends AbstractAsyncServer {
@Override
protected AbstractChannelPipelineFactory createPipelineFactory() {
+ boolean proxyFirst = true;
return new AbstractSSLAwareChannelPipelineFactory(
getTimeout(),
maxCurConnections,
maxCurConnectionsPerIP,
proxyRequired,
+ proxyFirst,
() -> secure,
getFrameHandlerFactory(),
new DefaultEventLoopGroup(16)) {
diff --git
a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
index 9b0af883a3..c76b826d75 100644
---
a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
+++
b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java
@@ -321,7 +321,7 @@ public class IMAPServer extends
AbstractConfigurableAsyncServer implements ImapC
Encryption secure = getEncryption();
if (secure != null && !secure.isStartTLS()) {
- if (proxyRequired) {
+ if (proxyRequired && proxyFirst) {
channel.pipeline().addAfter("proxyInformationHandler",
SSL_HANDLER, secure.sslHandler());
} else {
channel.pipeline().addFirst(SSL_HANDLER,
secure.sslHandler());
diff --git
a/server/protocols/protocols-library/src/main/java/org/apache/james/protocols/lib/netty/AbstractConfigurableAsyncServer.java
b/server/protocols/protocols-library/src/main/java/org/apache/james/protocols/lib/netty/AbstractConfigurableAsyncServer.java
index 1be20371d1..8508006ef9 100644
---
a/server/protocols/protocols-library/src/main/java/org/apache/james/protocols/lib/netty/AbstractConfigurableAsyncServer.java
+++
b/server/protocols/protocols-library/src/main/java/org/apache/james/protocols/lib/netty/AbstractConfigurableAsyncServer.java
@@ -90,6 +90,7 @@ public abstract class AbstractConfigurableAsyncServer
/** The name of the parameter defining the service hello name. */
public static final String PROXY_REQUIRED = "proxyRequired";
+ public static final String PROXY_FIRST = "proxyFirst";
public static final int DEFAULT_MAX_EXECUTOR_COUNT = 16;
@@ -98,6 +99,7 @@ public abstract class AbstractConfigurableAsyncServer
private boolean enabled;
protected boolean proxyRequired;
+ protected boolean proxyFirst;
protected int connPerIP;
@@ -251,6 +253,7 @@ public abstract class AbstractConfigurableAsyncServer
Optional.ofNullable(config.getBoolean("useEpoll",
null)).ifPresent(this::setUseEpoll);
proxyRequired = config.getBoolean(PROXY_REQUIRED, false);
+ proxyFirst = config.getBoolean(PROXY_FIRST, false);
doConfigure(config);
@@ -488,7 +491,7 @@ public abstract class AbstractConfigurableAsyncServer
@Override
protected AbstractChannelPipelineFactory createPipelineFactory() {
return new AbstractSSLAwareChannelPipelineFactory<>(getTimeout(),
connectionLimit, connPerIP,
- proxyRequired,
+ proxyRequired, proxyFirst,
this::getEncryption, getFrameHandlerFactory(), getExecutorGroup())
{
@Override
diff --git a/src/site/xdoc/server/config-imap4.xml
b/src/site/xdoc/server/config-imap4.xml
index b935701f46..f1ee2717b2 100644
--- a/src/site/xdoc/server/config-imap4.xml
+++ b/src/site/xdoc/server/config-imap4.xml
@@ -86,13 +86,18 @@
<dt><strong>maxQueueSize</strong></dt>
<dd>Upper bound to the IMAP throttler queue. Upon burst, requests that
cannot be queued are rejected and not executed.
Integer, defaults to 4096, must be positive, 0 means no queue.</dd>
- <dt><strong>handler.proxyRequired</strong></dt>
+ <dt><strong>proxyRequired</strong></dt>
<dd>
Enables proxy support for this service for incoming connections.
HAProxy's protocol
(https://www.haproxy.org/download/2.7/doc/proxy-protocol.txt) is
used and might be compatible
with other proxies (e.g. traefik). If enabled, it is *required* to
initiate the connection
using HAProxy's proxy protocol.
</dd>
+ <dt><strong>proxyFirst</strong></dt>
+ <dd>Whether proxy frames should be handled before SSL handshakes. This
allows setting either the loadbalancer in TCP mode
+ (so transparent for SSL then Proxy frames needs to be handled
first) or set up SSL termination between proxy and server
+ (more suited for some cloud vendors). Defaults to true (TCP
transparent).
+ </dd>
<dt><strong>handler.handlerchain</strong></dt>
<dd>This loads the core CommandHandlers. Only remove this if you
really
know what you are doing</dd>
diff --git a/src/site/xdoc/server/config-smtp-lmtp.xml
b/src/site/xdoc/server/config-smtp-lmtp.xml
index 39575fa106..4ffdd2f049 100644
--- a/src/site/xdoc/server/config-smtp-lmtp.xml
+++ b/src/site/xdoc/server/config-smtp-lmtp.xml
@@ -81,6 +81,11 @@
with other proxies (e.g. traefik). If enabled, it is *required* to
initiate the connection
using HAProxy's proxy protocol.
</dd>
+ <dt><strong>proxyFirst</strong></dt>
+ <dd>Whether proxy frames should be handled before SSL handshakes. This
allows setting either the loadbalancer in TCP mode
+ (so transparent for SSL then Proxy frames needs to be handled
first) or set up SSL termination between proxy and server
+ (more suited for some cloud vendors). Defaults to true (TCP
transparent).
+ </dd>
<dt><strong>authRequired</strong></dt>
<dd>(deprecated) use auth.announce instead.
This is an optional tag with a boolean body. If true, then the
server will
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]