JAMES-2004 Starting JMAP should be made optional, as well as providing it's configuration file
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/67e769c1 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/67e769c1 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/67e769c1 Branch: refs/heads/master Commit: 67e769c1db3bc99301fce3a44a59a2857a475c7c Parents: 445680d Author: benwa <btell...@linagora.com> Authored: Tue Apr 18 08:35:59 2017 +0700 Committer: benwa <btell...@linagora.com> Committed: Fri Apr 21 08:27:36 2017 +0700 ---------------------------------------------------------------------- .../destination/conf/jmap.properties | 2 + .../cassandra/destination/conf/jmap.properties | 2 + .../sample-configuration/jmap.properties | 2 + .../java/org/apache/james/jmap/JMAPModule.java | 16 ++++- .../modules/protocols/JMAPServerModule.java | 16 +++-- .../james/modules/TestJMAPServerModule.java | 1 + .../apache/james/jmap/JMAPConfiguration.java | 35 +++++++--- .../java/org/apache/james/jmap/JMAPServer.java | 73 ++++++++++---------- .../james/jmap/JMAPConfigurationTest.java | 28 +++++++- .../crypto/JamesSignatureHandlerProvider.java | 1 + 10 files changed, 122 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/dockerfiles/run/guice/cassandra-ldap/destination/conf/jmap.properties ---------------------------------------------------------------------- diff --git a/dockerfiles/run/guice/cassandra-ldap/destination/conf/jmap.properties b/dockerfiles/run/guice/cassandra-ldap/destination/conf/jmap.properties index 34ab451..63e6702 100644 --- a/dockerfiles/run/guice/cassandra-ldap/destination/conf/jmap.properties +++ b/dockerfiles/run/guice/cassandra-ldap/destination/conf/jmap.properties @@ -1,5 +1,7 @@ # Configuration file for JMAP +enabled=true + tls.keystoreURL=file://conf/keystore tls.secret=james72laBalle http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/dockerfiles/run/guice/cassandra/destination/conf/jmap.properties ---------------------------------------------------------------------- diff --git a/dockerfiles/run/guice/cassandra/destination/conf/jmap.properties b/dockerfiles/run/guice/cassandra/destination/conf/jmap.properties index 34ab451..63e6702 100644 --- a/dockerfiles/run/guice/cassandra/destination/conf/jmap.properties +++ b/dockerfiles/run/guice/cassandra/destination/conf/jmap.properties @@ -1,5 +1,7 @@ # Configuration file for JMAP +enabled=true + tls.keystoreURL=file://conf/keystore tls.secret=james72laBalle http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/server/container/guice/memory-guice/sample-configuration/jmap.properties ---------------------------------------------------------------------- diff --git a/server/container/guice/memory-guice/sample-configuration/jmap.properties b/server/container/guice/memory-guice/sample-configuration/jmap.properties index 071bafb..709ed8e 100644 --- a/server/container/guice/memory-guice/sample-configuration/jmap.properties +++ b/server/container/guice/memory-guice/sample-configuration/jmap.properties @@ -1,5 +1,7 @@ # Configuration file for JMAP +enabled=true + tls.keystoreURL=file://conf/keystore tls.secret=james72laBalle http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPModule.java ---------------------------------------------------------------------- diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPModule.java index de72639..86f3f5e 100644 --- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPModule.java +++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPModule.java @@ -18,6 +18,7 @@ ****************************************************************/ package org.apache.james.jmap; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.EnumSet; import java.util.List; @@ -44,6 +45,8 @@ import org.apache.james.queue.api.MailQueueItemDecoratorFactory; import org.apache.james.transport.matchers.RecipientIsLocal; import org.apache.james.utils.ConfigurationPerformer; import org.apache.james.utils.PropertiesProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.github.fge.lambdas.Throwing; import com.google.common.base.Charsets; @@ -58,6 +61,7 @@ import com.google.inject.multibindings.Multibinder; public class JMAPModule extends AbstractModule { private static final int DEFAULT_JMAP_PORT = 80; + private static final Logger LOGGER = LoggerFactory.getLogger(JMAPModule.class); @Override protected void configure() { @@ -82,13 +86,21 @@ public class JMAPModule extends AbstractModule { @Provides @Singleton JMAPConfiguration provideConfiguration(PropertiesProvider propertiesProvider, FileSystem fileSystem) throws ConfigurationException, IOException{ - PropertiesConfiguration configuration = propertiesProvider.getConfiguration("jmap"); - return JMAPConfiguration.builder() + try { + PropertiesConfiguration configuration = propertiesProvider.getConfiguration("jmap"); + return JMAPConfiguration.builder() + .enabled(configuration.getBoolean("enabled", true)) .keystore(configuration.getString("tls.keystoreURL")) .secret(configuration.getString("tls.secret")) .jwtPublicKeyPem(loadPublicKey(fileSystem, Optional.ofNullable(configuration.getString("jwt.publickeypem.url")))) .port(configuration.getInt("jmap.port", DEFAULT_JMAP_PORT)) .build(); + } catch (FileNotFoundException e) { + LOGGER.warn("Could not find JMAP configuration file. JMAP server will not be enabled."); + return JMAPConfiguration.builder() + .disable() + .build(); + } } @Provides http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java ---------------------------------------------------------------------- diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java index a04e1db..aa1cc00 100644 --- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java +++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java @@ -22,6 +22,8 @@ package org.apache.james.modules.protocols; import java.security.Security; import java.util.List; +import org.apache.commons.configuration.HierarchicalConfiguration; +import org.apache.james.jmap.JMAPConfiguration; import org.apache.james.jmap.JMAPModule; import org.apache.james.jmap.JMAPServer; import org.apache.james.jmap.crypto.JamesSignatureHandler; @@ -40,6 +42,8 @@ import com.google.inject.multibindings.Multibinder; public class JMAPServerModule extends AbstractModule { + private static final HierarchicalConfiguration NULL_CONFIGURATION = null; + @Override protected void configure() { install(new JMAPModule()); @@ -52,19 +56,23 @@ public class JMAPServerModule extends AbstractModule { private final JMAPServer server; private final JamesSignatureHandler signatureHandler; + private final JMAPConfiguration jmapConfiguration; @Inject - public JMAPModuleConfigurationPerformer(JMAPServer server, JamesSignatureHandler signatureHandler) { + public JMAPModuleConfigurationPerformer(JMAPServer server, JamesSignatureHandler signatureHandler, JMAPConfiguration jmapConfiguration) { this.server = server; this.signatureHandler = signatureHandler; + this.jmapConfiguration = jmapConfiguration; } @Override public void initModule() { try { - signatureHandler.init(); - server.configure(null); - registerPEMWithSecurityProvider(); + if (jmapConfiguration.isEnabled()) { + signatureHandler.init(); + server.configure(NULL_CONFIGURATION); + registerPEMWithSecurityProvider(); + } } catch (Exception e) { Throwables.propagate(e); } http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/server/container/guice/protocols/jmap/src/test/java/org/apache/james/modules/TestJMAPServerModule.java ---------------------------------------------------------------------- diff --git a/server/container/guice/protocols/jmap/src/test/java/org/apache/james/modules/TestJMAPServerModule.java b/server/container/guice/protocols/jmap/src/test/java/org/apache/james/modules/TestJMAPServerModule.java index 6512fac..f23d3b6 100644 --- a/server/container/guice/protocols/jmap/src/test/java/org/apache/james/modules/TestJMAPServerModule.java +++ b/server/container/guice/protocols/jmap/src/test/java/org/apache/james/modules/TestJMAPServerModule.java @@ -59,6 +59,7 @@ public class TestJMAPServerModule extends AbstractModule{ @Singleton JMAPConfiguration provideConfiguration() throws FileNotFoundException, ConfigurationException{ return JMAPConfiguration.builder() + .enable() .keystore("keystore") .secret("james72laBalle") .jwtPublicKeyPem(Optional.of(PUBLIC_PEM_KEY)) http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPConfiguration.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPConfiguration.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPConfiguration.java index 35d0496..e194e0f 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPConfiguration.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPConfiguration.java @@ -33,18 +33,30 @@ public class JMAPConfiguration { public static class Builder { private String keystore; private String secret; - private Optional<String> jwtPublicKeyPem; + private Optional<Boolean> enabled = Optional.empty(); + private Optional<String> jwtPublicKeyPem = Optional.empty(); private Optional<Integer> port = Optional.empty(); - private Builder() { - jwtPublicKeyPem = Optional.empty(); - } + private Builder() {} public Builder keystore(String keystore) { this.keystore = keystore; return this; } + public Builder enabled(boolean enabled) { + this.enabled = Optional.of(enabled); + return this; + } + + public Builder enable() { + return enabled(true); + } + + public Builder disable() { + return enabled(false); + } + public Builder secret(String secret) { this.secret = secret; return this; @@ -67,24 +79,31 @@ public class JMAPConfiguration { } public JMAPConfiguration build() { - Preconditions.checkState(!Strings.isNullOrEmpty(keystore), "'keystore' is mandatory"); - Preconditions.checkState(!Strings.isNullOrEmpty(secret), "'secret' is mandatory"); - return new JMAPConfiguration(keystore, secret, jwtPublicKeyPem, port); + Preconditions.checkState(enabled.isPresent(), "You should specify if JMAP server should be started"); + Preconditions.checkState(!enabled.get() || !Strings.isNullOrEmpty(keystore), "'keystore' is mandatory"); + Preconditions.checkState(!enabled.get() || !Strings.isNullOrEmpty(secret), "'secret' is mandatory"); + return new JMAPConfiguration(enabled.get(), keystore, secret, jwtPublicKeyPem, port); } } + private final boolean enabled; private final String keystore; private final String secret; private final Optional<String> jwtPublicKeyPem; private final Optional<Integer> port; - @VisibleForTesting JMAPConfiguration(String keystore, String secret, Optional<String> jwtPublicKeyPem, Optional<Integer> port) { + @VisibleForTesting JMAPConfiguration(boolean enabled, String keystore, String secret, Optional<String> jwtPublicKeyPem, Optional<Integer> port) { + this.enabled = enabled; this.keystore = keystore; this.secret = secret; this.jwtPublicKeyPem = jwtPublicKeyPem; this.port = port; } + public boolean isEnabled() { + return enabled; + } + public String getKeystore() { return keystore; } http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServer.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServer.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServer.java index de3ac75..a6ac629 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServer.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServer.java @@ -21,6 +21,8 @@ package org.apache.james.jmap; import static org.apache.james.jmap.BypassAuthOnRequestMethod.bypass; +import java.util.Optional; + import javax.annotation.PreDestroy; import javax.inject.Inject; @@ -31,42 +33,45 @@ import org.apache.james.http.jetty.Configuration.Builder; import org.apache.james.http.jetty.JettyHttpServer; import org.apache.james.lifecycle.api.Configurable; -import com.google.common.base.Throwables; +import com.github.fge.lambdas.Throwing; public class JMAPServer implements Configurable { - private final JettyHttpServer server; + private final Optional<JettyHttpServer> server; @Inject private JMAPServer(JMAPConfiguration jmapConfiguration, AuthenticationServlet authenticationServlet, JMAPServlet jmapServlet, DownloadServlet downloadServlet, UploadServlet uploadServlet, AuthenticationFilter authenticationFilter, UserProvisioningFilter userProvisioningFilter, DefaultMailboxesProvisioningFilter defaultMailboxesProvisioningFilter) { - - server = JettyHttpServer.create( + if (jmapConfiguration.isEnabled()) { + server = Optional.of(JettyHttpServer.create( configurationBuilderFor(jmapConfiguration) - .serve(JMAPUrls.AUTHENTICATION) - .with(authenticationServlet) - .filter(JMAPUrls.AUTHENTICATION) - .with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("POST").and("OPTIONS").only())) - .only() - .serve(JMAPUrls.JMAP) - .with(jmapServlet) - .filter(JMAPUrls.JMAP) - .with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("OPTIONS").only())) - .and(userProvisioningFilter) - .and(defaultMailboxesProvisioningFilter) - .only() - .serveAsOneLevelTemplate(JMAPUrls.DOWNLOAD) - .with(downloadServlet) - .filterAsOneLevelTemplate(JMAPUrls.DOWNLOAD) - .with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("OPTIONS").only())) - .only() - .serve(JMAPUrls.UPLOAD) - .with(uploadServlet) - .filterAsOneLevelTemplate(JMAPUrls.UPLOAD) - .with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("OPTIONS").only())) - .only() - .build()); + .serve(JMAPUrls.AUTHENTICATION) + .with(authenticationServlet) + .filter(JMAPUrls.AUTHENTICATION) + .with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("POST").and("OPTIONS").only())) + .only() + .serve(JMAPUrls.JMAP) + .with(jmapServlet) + .filter(JMAPUrls.JMAP) + .with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("OPTIONS").only())) + .and(userProvisioningFilter) + .and(defaultMailboxesProvisioningFilter) + .only() + .serveAsOneLevelTemplate(JMAPUrls.DOWNLOAD) + .with(downloadServlet) + .filterAsOneLevelTemplate(JMAPUrls.DOWNLOAD) + .with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("OPTIONS").only())) + .only() + .serve(JMAPUrls.UPLOAD) + .with(uploadServlet) + .filterAsOneLevelTemplate(JMAPUrls.UPLOAD) + .with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("OPTIONS").only())) + .only() + .build())); + } else { + server = Optional.empty(); + } } private Builder configurationBuilderFor(JMAPConfiguration jmapConfiguration) { @@ -81,23 +86,15 @@ public class JMAPServer implements Configurable { @Override public void configure(HierarchicalConfiguration config) throws ConfigurationException { - try { - server.start(); - } catch (Exception e) { - Throwables.propagate(e); - } + server.ifPresent(Throwing.consumer(JettyHttpServer::start).sneakyThrow()); } @PreDestroy public void stop() { - try { - server.stop(); - } catch (Exception e) { - Throwables.propagate(e); - } + server.ifPresent(Throwing.consumer(JettyHttpServer::stop).sneakyThrow()); } public int getPort() { - return server.getPort(); + return server.map(JettyHttpServer::getPort).orElseThrow(() -> new RuntimeException("JMAP server was disabled. No port bound")); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPConfigurationTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPConfigurationTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPConfigurationTest.java index e7a427e..4ffce68 100644 --- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPConfigurationTest.java +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPConfigurationTest.java @@ -28,9 +28,13 @@ import org.junit.Test; public class JMAPConfigurationTest { + public static final boolean ENABLED = true; + public static final boolean DISABLED = false; + @Test public void buildShouldThrowWhenKeystoreIsNull() { assertThatThrownBy(() -> JMAPConfiguration.builder() + .enable() .keystore(null) .build()) .isInstanceOf(IllegalStateException.class) @@ -40,6 +44,7 @@ public class JMAPConfigurationTest { @Test public void buildShouldThrowWhenKeystoreIsEmpty() { assertThatThrownBy(() -> JMAPConfiguration.builder() + .enable() .keystore("") .build()) .isInstanceOf(IllegalStateException.class) @@ -49,6 +54,7 @@ public class JMAPConfigurationTest { @Test public void buildShouldThrowWhenSecretIsNull() { assertThatThrownBy(() -> JMAPConfiguration.builder() + .enable() .keystore("keystore") .secret(null) .build()) @@ -59,6 +65,7 @@ public class JMAPConfigurationTest { @Test public void buildShouldThrowWhenSecretIsEmpty() { assertThatThrownBy(() -> JMAPConfiguration.builder() + .enable() .keystore("keystore") .secret("") .build()) @@ -69,6 +76,7 @@ public class JMAPConfigurationTest { @Test public void buildShouldThrowWhenJwtPublicKeyPemIsNull() { assertThatThrownBy(() -> JMAPConfiguration.builder() + .enable() .keystore("keystore") .secret("secret") .jwtPublicKeyPem(null) @@ -78,9 +86,10 @@ public class JMAPConfigurationTest { @Test public void buildShouldWorkWhenRandomPort() { - JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration("keystore", "secret", Optional.of("file://conf/jwt_publickey"), Optional.empty()); + JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration(ENABLED, "keystore", "secret", Optional.of("file://conf/jwt_publickey"), Optional.empty()); JMAPConfiguration jmapConfiguration = JMAPConfiguration.builder() + .enable() .keystore("keystore") .secret("secret") .jwtPublicKeyPem(Optional.of("file://conf/jwt_publickey")) @@ -91,9 +100,10 @@ public class JMAPConfigurationTest { @Test public void buildShouldWorkWhenFixedPort() { - JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration("keystore", "secret", Optional.of("file://conf/jwt_publickey"), Optional.of(80)); + JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration(ENABLED, "keystore", "secret", Optional.of("file://conf/jwt_publickey"), Optional.of(80)); JMAPConfiguration jmapConfiguration = JMAPConfiguration.builder() + .enable() .keystore("keystore") .secret("secret") .jwtPublicKeyPem(Optional.of("file://conf/jwt_publickey")) @@ -101,4 +111,18 @@ public class JMAPConfigurationTest { .build(); assertThat(jmapConfiguration).isEqualToComparingFieldByField(expectedJMAPConfiguration); } + + @Test + public void buildShouldWorkWhenDisabled() { + String keystore = null; + String secret = null; + Optional<String> jwtPublicKeyPem = Optional.empty(); + Optional<Integer> port = Optional.empty(); + JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration(DISABLED, keystore, secret, jwtPublicKeyPem, port); + + JMAPConfiguration jmapConfiguration = JMAPConfiguration.builder() + .disable() + .build(); + assertThat(jmapConfiguration).isEqualToComparingFieldByField(expectedJMAPConfiguration); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/67e769c1/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/JamesSignatureHandlerProvider.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/JamesSignatureHandlerProvider.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/JamesSignatureHandlerProvider.java index 06e3bd3..f3d0656 100644 --- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/JamesSignatureHandlerProvider.java +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/crypto/JamesSignatureHandlerProvider.java @@ -48,6 +48,7 @@ public class JamesSignatureHandlerProvider { }; JamesSignatureHandler signatureHandler = new JamesSignatureHandler(fileSystem, JMAPConfiguration.builder() + .enable() .keystore("keystore") .secret("james72laBalle") .build()); --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org