mirror of https://github.com/shred/acme4j
Add EmailProcessor.Builder for configuring verification
parent
0dff988b26
commit
9bddc07ed3
|
@ -16,6 +16,10 @@ package org.shredzone.acme4j.smime.email;
|
|||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.cert.PKIXParameters;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -36,7 +40,6 @@ import org.shredzone.acme4j.exception.AcmeProtocolException;
|
|||
import org.shredzone.acme4j.smime.challenge.EmailReply00Challenge;
|
||||
import org.shredzone.acme4j.smime.exception.AcmeInvalidMessageException;
|
||||
import org.shredzone.acme4j.smime.wrapper.Mail;
|
||||
import org.shredzone.acme4j.smime.wrapper.SignedMail;
|
||||
import org.shredzone.acme4j.smime.wrapper.SignedMailBuilder;
|
||||
import org.shredzone.acme4j.smime.wrapper.SimpleMail;
|
||||
|
||||
|
@ -57,11 +60,11 @@ public final class EmailProcessor {
|
|||
private final AtomicReference<EmailReply00Challenge> challengeRef = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* Processes the given e-mail message.
|
||||
* Processes the given plain e-mail message.
|
||||
* <p>
|
||||
* Note that according to RFC-8823, the challenge message must be signed using either
|
||||
* DKIM or S/MIME. This method does not do any DKIM or S/MIME validation, and assumes
|
||||
* that this has already been done by the inbound MTA.
|
||||
* that this has already been done in a previous stage.
|
||||
*
|
||||
* @param message
|
||||
* E-mail that was received from the CA. The inbound MTA has already taken
|
||||
|
@ -73,7 +76,38 @@ public final class EmailProcessor {
|
|||
*/
|
||||
public static EmailProcessor plainMessage(Message message)
|
||||
throws AcmeInvalidMessageException {
|
||||
return new EmailProcessor(new SimpleMail(message));
|
||||
return builder().skipVerification().build(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the given signed e-mail message.
|
||||
* <p>
|
||||
* This method expects an S/MIME signed message. The signature must use a certificate
|
||||
* that can be validated using Java's cacert truststore. Strict validation rules are
|
||||
* applied.
|
||||
* <p>
|
||||
* Use the {@link #builder()} method if you need to configure the validation process.
|
||||
*
|
||||
* @param message
|
||||
* S/MIME signed e-mail that was received from the CA.
|
||||
* @return EmailProcessor for this e-mail
|
||||
* @throws AcmeInvalidMessageException
|
||||
* if a validation failed, and the message <em>must</em> be rejected.
|
||||
* @since 2.16
|
||||
*/
|
||||
public static EmailProcessor signedMessage(Message message)
|
||||
throws AcmeInvalidMessageException {
|
||||
return builder().build(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Builder} for building an {@link EmailProcessor} with individual
|
||||
* configuration.
|
||||
*
|
||||
* @since 2.16
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,16 +130,21 @@ public final class EmailProcessor {
|
|||
* @throws AcmeInvalidMessageException
|
||||
* if a validation failed, and the message <em>must</em> be rejected.
|
||||
* @since 2.15
|
||||
* @deprecated Use {@link #signedMessage(Message)} or {@link #builder()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static EmailProcessor smimeMessage(Message message, Session mailSession,
|
||||
X509Certificate signCert, boolean strict)
|
||||
throws AcmeInvalidMessageException {
|
||||
SignedMail mail = new SignedMailBuilder()
|
||||
.withSignCert(signCert)
|
||||
.relaxed(!strict)
|
||||
.withMailSession(mailSession)
|
||||
.build(message);
|
||||
return new EmailProcessor(mail);
|
||||
Builder builder = builder()
|
||||
.mailSession(mailSession)
|
||||
.certificate(signCert);
|
||||
if (strict) {
|
||||
builder.strict();
|
||||
} else {
|
||||
builder.relaxed();
|
||||
}
|
||||
return builder.build(message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -408,4 +447,124 @@ public final class EmailProcessor {
|
|||
R apply(M message) throws MessagingException;
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link EmailProcessor}.
|
||||
* <p>
|
||||
* Use {@link EmailProcessor#builder()} to generate an instance.
|
||||
*
|
||||
* @since 2.16
|
||||
*/
|
||||
public static class Builder {
|
||||
private boolean unsigned = false;
|
||||
private SignedMailBuilder builder = new SignedMailBuilder();
|
||||
|
||||
private Builder() {
|
||||
// Private constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips signature and header verification. Use only if the message has already
|
||||
* been verified in a previous stage (e.g. by the MTA) or for testing purposes.
|
||||
*/
|
||||
public Builder skipVerification() {
|
||||
this.unsigned = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the standard cacerts truststore for signature verification. This is the
|
||||
* default.
|
||||
*/
|
||||
public Builder caCerts() {
|
||||
builder.withCaCertsTrustStore();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given truststore for signature verification.
|
||||
*
|
||||
* @param trustStore
|
||||
* {@link KeyStore} of the truststore to be used.
|
||||
*/
|
||||
public Builder trustStore(KeyStore trustStore) {
|
||||
try {
|
||||
builder.withTrustStore(trustStore);
|
||||
} catch (KeyStoreException | InvalidAlgorithmParameterException ex) {
|
||||
throw new IllegalArgumentException("Cannot use trustStore", ex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given certificate for signature verification.
|
||||
*
|
||||
* @param certificate
|
||||
* {@link X509Certificate} of the CA
|
||||
*/
|
||||
public Builder certificate(X509Certificate certificate) {
|
||||
builder.withSignCert(certificate);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given {@link PKIXParameters}.
|
||||
*
|
||||
* @param param
|
||||
* {@link PKIXParameters} to be used for signature verification.
|
||||
*/
|
||||
public Builder pkixParameters(PKIXParameters param) {
|
||||
builder.withPKIXParameters(param);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given mail {@link Session} for accessing the signed message body. A
|
||||
* simple default session is used otherwise, which is usually sufficient.
|
||||
*
|
||||
* @param session
|
||||
* {@link Session} to be used for accessing the message body.
|
||||
*/
|
||||
public Builder mailSession(Session session) {
|
||||
builder.withMailSession(session);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs strict checks. Secured headers must exactly match their unsecured
|
||||
* counterparts. This is the default.
|
||||
*/
|
||||
public Builder strict() {
|
||||
builder.relaxed(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs relaxed checks. Secured headers might differ in whitespaces or case of
|
||||
* the field names. Use this if your MTA has mangled the envelope header.
|
||||
*/
|
||||
public Builder relaxed() {
|
||||
builder.relaxed(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an {@link EmailProcessor} for the given {@link Message} using the
|
||||
* current configuration.
|
||||
*
|
||||
* @param message
|
||||
* {@link Message} to create an {@link EmailProcessor} for.
|
||||
* @return The generated {@link EmailProcessor}
|
||||
* @throws AcmeInvalidMessageException
|
||||
* if the message fails to be verified. If this exception is thrown, the
|
||||
* message MUST be rejected, and MUST NOT be used for certification.
|
||||
*/
|
||||
public EmailProcessor build(Message message) throws AcmeInvalidMessageException {
|
||||
if (unsigned) {
|
||||
return new EmailProcessor(new SimpleMail(message));
|
||||
} else {
|
||||
return new EmailProcessor(builder.build(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -67,6 +67,14 @@ public class SignedMailBuilder {
|
|||
@Nullable
|
||||
private PKIXParameters pkixParameters = null;
|
||||
|
||||
/**
|
||||
* Uses the standard cacerts truststore. This is the default.
|
||||
*/
|
||||
public SignedMailBuilder withCaCertsTrustStore() {
|
||||
pkixParameters = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given truststore for certificate validation.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue