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 <btell...@linagora.com>
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: notifications-unsubscr...@james.apache.org
For additional commands, e-mail: notifications-h...@james.apache.org

Reply via email to