You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by "Benoit Tellier (Jira)" <se...@james.apache.org> on 2021/09/03 07:38:00 UTC

[jira] [Created] (JAMES-3645) RemoteDelivery sslEnable parameter have no effect

Benoit Tellier created JAMES-3645:
-------------------------------------

             Summary: RemoteDelivery sslEnable parameter have no effect
                 Key: JAMES-3645
                 URL: https://issues.apache.org/jira/browse/JAMES-3645
             Project: James Server
          Issue Type: Improvement
            Reporter: Benoit Tellier


h3. Description

As an administrator I wish to secure my outgoing emails using SSL (SMTPS on port 465), and default to SMTP on port 25 (where STARTTLS can be used opportunistically).

This need is a recurring one for Gitter users (often asked, known for years to be buggy).

h3. Setting up test James servers

I did write a simple docker-compose.yml file to experiment this:

{code:java}
version: '3'

services:

  james1:
    image: apache/james:memory-latest
    container_name: james1
    hostname: james1
    volumes:
      - $PWD/keystore:/root/conf/keystore

  james2:
    image: apache/james:memory-latest
    container_name: james2
    hostname: james2
    volumes:
      - $PWD/keystore:/root/conf/keystore
{code}

I do embed two RcptHooks to diagnose where remoteDelivery connects on james2:


{code:java}
package org.apache.james;

import org.apache.james.core.MailAddress;
import org.apache.james.core.MaybeSender;
import org.apache.james.protocols.smtp.SMTPSession;
import org.apache.james.protocols.smtp.hook.HookResult;
import org.apache.james.protocols.smtp.hook.RcptHook;

public class SoutRcptHook implements RcptHook {
    @Override
    public HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt) {
        System.out.println("  <---> SSL activated: " + sender.asPrettyString() + " sends a message securely to " + rcpt.asString());
        return HookResult.DECLINED;
    }
{code}

And

{code:java}
package org.apache.james;

import org.apache.james.core.MailAddress;
import org.apache.james.core.MaybeSender;
import org.apache.james.protocols.smtp.SMTPSession;
import org.apache.james.protocols.smtp.hook.HookResult;
import org.apache.james.protocols.smtp.hook.RcptHook;

public class NoSSLRcptHook implements RcptHook {
    @Override
    public HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt) {
        System.out.println("  <---> NO SSL: " + sender.asPrettyString() + " sends a message securely to " + rcpt.asString());
        return HookResult.DECLINED;
    }
}
{code}

Which then ellows configuring the SMTP server:

{code:java}
<smtpservers>
    <smtpserver enabled="true">
        <jmxName>smtpserver-global</jmxName>
        <bind>0.0.0.0:25</bind>
        <tls socketTLS="false" startTLS="true">
            <keystore>file://conf/keystore</keystore>
            <secret>james72laBalle</secret>
            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
            <algorithm>SunX509</algorithm>
        </tls>
        <smtpGreeting>Apache JAMES awesome SMTP Server</smtpGreeting>
        <handlerchain>
            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
            <handler class="org.apache.james.NoSSLRcptHook"/>
        </handlerchain>
    </smtpserver>
    <smtpserver enabled="true">
        <jmxName>smtpserver-TLS</jmxName>
        <bind>0.0.0.0:465</bind>
        <tls socketTLS="true" startTLS="false">
            <keystore>file://conf/keystore</keystore>
            <secret>james72laBalle</secret>
            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
            <algorithm>SunX509</algorithm>
        </tls>
        <smtpGreeting>Apache JAMES awesome SMTP Server</smtpGreeting>
        <handlerchain>
            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
            <handler class="org.apache.james.SoutRcptHook"/>
        </handlerchain>
    </smtpserver>
</smtpservers>
{code}

We then can review logs to know which port was eventually used to receive emails (smtp logs also tells us if STARTTLS is used).

I expect `sslEnable` parameter to govern this opportunistic SSL connection. Thus RemoteDelivery configuration looks like this:

{code:java}
        <processor state="relay" enableJmx="true">
            <mailet match="All" class="RemoteDelivery">
                <outgoingQueue>outgoing</outgoingQueue>
                <bounceProcessor>bounces</bounceProcessor>
                <debug>true</debug>
                <mail.smtp.ssl.trust>*</mail.smtp.ssl.trust>
                <sslEnable>true</sslEnable>
                <startTLS>true</startTLS>
            </mailet>
        </processor>
{code}

We then can create some test data and send a mail from james1 to james2:

{code:java}
docker-compose up -d

docker exec james1 james-cli adddomain james1
docker exec james2 james-cli adddomain james2
docker exec james1 james-cli adduser bob@james1 123456
docker exec james2 james-cli adduser bob@james2 123456
docker inspect james1

telnet [james1] 25
auth login
Ym9iQGphbWVzMQ==
MTIzNDU2
ehlo james1
mail from: <bo...@james1>
rcpt to: <bo...@james2>
data

Subject: rueooerwbwerb

veriobwerobwerbr
rwebeberber
.
{code}

Will generate james1 to remote-deliver a mail to james2, and we can in the process diagnose the remote delivery behaviour between the two.

h3. Actual behaviour

james1 attepts an SSL connection on port 25:


{code:java}
james1    | 06:56:43.405 [DEBUG] o.a.j.t.m.r.d.MailDelivrer - Could not connect to SMTP host: 172.30.0.2, port: 25
james1    | javax.net.ssl.SSLException: Unsupported or unrecognized SSL message
james1    |     at java.base/sun.security.ssl.SSLSocketInputRecord.handleUnknownRecord(SSLSocketInputRecord.java:451)
james1    |     at java.base/sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:175)
james1    |     at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:110)
james1    |     at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1418)
james1    |     at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1324)
james1    |     at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:440)
james1    |     at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:411)
james1    |     at com.sun.mail.util.SocketFetcher.configureSSLSocket(SocketFetcher.java:626)
james1    |     at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:400)
james1    |     at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:238)
james1    |     at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2175)
james1    |     at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:740)
{code}

And james2 do not recognizes the commands:

{code:java}
james2    | 06:56:43.410 [DEBUG] o.a.j.p.a.h.CommandDispatcher - org.apache.james.protocols.api.handler.CommandDispatcher received: ZVVF�������E�F�8T�E'F��LO��#���
james2    | 06:56:43.411 [DEBUG] o.a.j.p.a.h.CommandDispatcher - Lookup command handler for command: ZVVF�������E�F�8T�E'F��LO��#���
james2    | 06:56:43.437 [DEBUG] o.a.j.p.a.h.CommandHandlerResultLogger - org.apache.james.protocols.smtp.core.UnknownCmdHandler: [500 5.5.1 Command ZVVF�������E�F�8T�E'F��LO��#��� unrecognized.]
james2    | 06:56:43.441 [DEBUG] o.a.j.p.a.h.CommandDispatcher - org.apache.james.protocols.api.handler.CommandDispatcher received: �5��98�#�'<�%�)G@�  �/��32��
james2    | 06:56:43.442 [DEBUG] o.a.j.p.a.h.CommandDispatcher - Lookup command handler for command: �5��98�#�'<�%�)G@� �/��32��
james2    | 06:56:43.442 [DEBUG] o.a.j.p.a.h.CommandHandlerResultLogger - org.apache.james.protocols.smtp.core.UnknownCmdHandler: [500 5.5.1 Command �5��98�#�'<�%�)G@� �/��32�� unrecognized.]
james2    | 06:56:43.443 [DEBUG] o.a.j.p.a.h.CommandDispatcher - org.apache.james.protocols.api.handler.CommandDispatcher received: ,*
james2    | 06:56:43.443 [DEBUG] o.a.j.p.a.h.CommandDispatcher - Lookup command handler for command: ,*
{code}

h3. Expected behaviour

We expect the mail to be sent over SSL.

We expect that if the target host do not support SSL on port 465 that we fallback to SMTP on port 25, and use STARTTLS.

h3. Interesting notice

 * MXHostAddressIterator is adding the protocol (smtp VS smtps) and the port (25 VS 465). While  setting these values according to SMTPS & 465 SSL is correctly performed.

The management of the fallback behavior however requires a fallback host address to be generated (SMTP + 25 after the SMTPS one), and also requires handling down the line in MailDelivrerToHost (use of two sessions, one for SMTP, one for SMTPS).

 * The use of self signed certificates for the distant server when using remoteDelivery :

{code:java}
<jvmFlag>-Djavax.net.ssl.trustStore=/root/conf/keystore</jvmFlag>
{code}





--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org