Uploaded image for project: 'James Server'
  1. James Server
  2. JAMES-3645

RemoteDelivery sslEnable parameter have no effect

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Closed
    • Major
    • Resolution: Fixed
    • None
    • 3.7.0
    • None
    • None

    Description

      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).

      Setting up test James servers

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

      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
      

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

      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;
          }
      

      And

      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;
          }
      }
      

      Which then ellows configuring the SMTP server:

      <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>
      

      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:

              <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>
      

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

      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: <bob@james1>
      rcpt to: <bob@james2>
      data
      
      Subject: rueooerwbwerb
      
      veriobwerobwerbr
      rwebeberber
      .
      

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

      Actual behaviour

      james1 attepts an SSL connection on port 25:

      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)
      

      And james2 do not recognizes the commands:

      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: ,*
      

      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.

      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 :
      <jvmFlag>-Djavax.net.ssl.trustStore=/root/conf/keystore</jvmFlag>
      
      • Fallback can be tested by disactivating the SSL SMTP port:
      <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.fastfail.ValidRcptHandler"/>
                  <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
                  <handler class="org.apache.james.NoSSLRcptHook"/>
              </handlerchain>
          </smtpserver>
          <smtpserver enabled="false">
              <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.fastfail.ValidRcptHandler"/>
                  <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
                  <handler class="org.apache.james.SoutRcptHook"/>
              </handlerchain>
          </smtpserver>
      </smtpservers>
      

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              btellier Benoit Tellier
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 1h 10m
                  1h 10m