Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JAMES-3823 SMTP Require TLS Option #2460

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

Maxxx873
Copy link
Contributor

JAMES-3823

Hi! The first step in the direction of SMTP Require TLS Option is a basic set of hooks. In the future I plan to enhance this PR by processing of new REQUIRETLS attribute, handling headers, remote delivery, etc.

Copy link
Contributor

@chibenwa chibenwa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello,

Thanks a LOT for contributions on the topic!

A first remark is that this pull request only tackles incoming SMTP while it necessarily have impact on outgoing SMTP settings: we need to have RemoteDelivery setting up the REQUIRETLS mail parameter if needed... (section 4). I know this will eventually get takkled before we could claim support for REQUIRETLS.

We also need to tackle section 5: preserving those parameters for Bounce and DSNBounce mailets.

@Maxxx873
Copy link
Contributor Author

Maxxx873 commented Dec 4, 2024

Hi! I'm still working. In this step, I added the requireStartTls() method for SmtpConfiguration in integration testing and implemented RemoteDelivery.

Copy link
Contributor

@chibenwa chibenwa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we need a way to test this:

GIVEN From REQUIRETLS
WHEN remoteDelivery speaks to a server that do NOT allow startTLS
THEN it fails

Don't we have a way to tweak MockSMTP into allowing testing this.

And yes and VERY good work, by the way.

@@ -123,17 +130,23 @@ public ExecutionResult tryDeliveryToHost(Mail mail, Collection<InternetAddress>
try {
transport = (SMTPTransport) session.getTransport(outgoingMailServer);
transport.setLocalHost(props.getProperty(inContext(session, "mail.smtp.localhost"), configuration.getHeloNameProvider().getHeloName()));
if (isTlsRequired(mail)) {
transport.setStartTLS(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 remarks:

  • If the transport layer is already configured with SSL there's no point setting SSL. That's the case EG relaying to a secure mail gateway other the internet.
  • If the receiver server do not support startTLS this need to throw.

@Maxxx873
Copy link
Contributor Author

IMO we need a way to test this:

GIVEN From REQUIRETLS WHEN remoteDelivery speaks to a server that do NOT allow startTLS THEN it fails

Don't we have a way to tweak MockSMTP into allowing testing this.

And yes and VERY good work, by the way.

Thanks so much for the review and remarks! Unfortunately, I don't know how to implement it correctly yet. I tried setting the MockSMTP behavior, but that's not what's needed as far as I understand. It is possible to make a tweak to MockSMTP to respond not only to commands, but also to parameters passed. Is it necessary? Further, it is not very clear how and at what point I can check the startTLS allowance for remoteDelivery. Also a question regarding Bounce and DSNBounce maillets. The REQUIRETLS email attribute will be saved as it is, what do I need to add additionally? I apologize for the large scope of questions.

Comment on lines 244 to 268
void remoteDeliveryShouldFailsWhenServerNotAllowStartTls(DockerMockSmtp mockSmtp) throws Exception {
testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
.login(FROM, PASSWORD);

MockSMTPBehavior startTlsBehavior = new MockSMTPBehavior(
MAIL_FROM,
Condition.MATCH_ALL,
new Response(COMMAND_PARAMETER_NOT_IMPLEMENTED_504, "The server has not implemented a command parameter"),
MockSMTPBehavior.NumberOfAnswersPolicy.anytime());

mockSmtp.getConfigurationClient().setBehaviors(List.of(startTlsBehavior));

SMTPSClient smtpClient = initSMTPSClient();
smtpClient.mail("<" + FROM + "> REQUIRETLS");
smtpClient.rcpt("<" + RECIPIENT + ">");
smtpClient.sendShortMessageData("A short message...");

String dsnMessage = testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
.login(FROM, PASSWORD)
.select(TestIMAPClient.INBOX)
.awaitMessageCount(awaitAtMostOneMinute, 1)
.readFirstMessage();

Assertions.assertThat(dsnMessage).contains("504 The server has not implemented a command parameter");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No what we want is the mock server to HIDE that it implements STARTTLS (in the EHLO capability).

When that's the case the relay of the mail should fail.

This is different from failing at MAIL FROM

(What I mean is that the test is inaccurate).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No what we want is the mock server to HIDE that it implements STARTTLS (in the EHLO capability).

When that's the case the relay of the mail should fail.

This is different from failing at MAIL FROM

(What I mean is that the test is inaccurate).

I agree with you, and I propose a new version of the test

@@ -131,6 +133,9 @@ public ExecutionResult tryDeliveryToHost(Mail mail, Collection<InternetAddress>
transport = (SMTPTransport) session.getTransport(outgoingMailServer);
transport.setLocalHost(props.getProperty(inContext(session, "mail.smtp.localhost"), configuration.getHeloNameProvider().getHeloName()));
connect(outgoingMailServer, transport);
if (!transport.getLastServerResponse().contains("STARTTLS")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should do this only if TLS is required

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn;t reviwing latest diff, sorry

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SmtpTlsMessageHook implements JamesMessageHook {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public class SmtpTlsMessageHook implements JamesMessageHook {
public class SmtpRequireTlsMessageHook implements JamesMessageHook {

import org.apache.james.protocols.smtp.hook.HeloHook;
import org.apache.james.protocols.smtp.hook.HookResult;

public class SmtpTlsEhloHook implements HeloHook {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public class SmtpTlsEhloHook implements HeloHook {
public class SmtpRequireTlsEhloHook implements HeloHook {

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SmtpTlsParameterHook implements MailParametersHook {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public class SmtpTlsParameterHook implements MailParametersHook {
public class SmtpRequireTlsParameterHook implements MailParametersHook {

Copy link
Contributor

@chibenwa chibenwa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good work.

I endorse this, and just find comments onto the naming of the hooks.

@Maxxx873
Copy link
Contributor Author

Very good work.

I endorse this, and just find comments onto the naming of the hooks.

Thank you! If there are any additional suggestions for improving this contribution, I am willing to follow up. It would be interesting if this could be tested on a test bench somehow. Thanks again for the code review and feedback on the work

@chibenwa
Copy link
Contributor

image

Test failures seems related.

Could you have a look?

@Maxxx873
Copy link
Contributor Author

image

Test failures seems related.

Could you have a look?

I assume firstly that in order for CI to work properly when running tests with MAIL FROM parameters with no value, we need to update the version of the mock smtp server in the docker hub. See:
#2489

@chibenwa
Copy link
Contributor

Will do tomorrow!

(sorry)

@chibenwa
Copy link
Contributor

linagora/mock-smtp-server:0.7 is pushed, as promissed.

I did also re-trigger a build.

@Maxxx873
Copy link
Contributor Author

linagora/mock-smtp-server:0.7 is pushed, as promissed.

I did also re-trigger a build.

Thanks for updating the mock smtp server. I see that some of the related tests failed, sorry, I will need more time to find the reason.

Copy link
Contributor

@Arsnael Arsnael left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error looks unrelated on the CI so I restarted the build!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants