This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit eff0d9f0c96087f65a4750c43ed7329250982d98 Author: Rene Cordier <[email protected]> AuthorDate: Fri Apr 10 15:05:11 2026 +0700 JAMES-4201 Add password.readonly and password.nodelete options to webadmin configuration --- .../james/modules/server/WebAdminServerModule.java | 2 + .../james/webadmin/WebAdminConfiguration.java | 45 ++++++++++++- .../james/webadmin/WebAdminConfigurationTest.java | 76 ++++++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) diff --git a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java index 9b9dcca561..bf42c4f701 100644 --- a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java +++ b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java @@ -156,6 +156,8 @@ public class WebAdminServerModule extends AbstractModule { .maxThreadCount(Optional.ofNullable(configurationFile.getInteger("maxThreadCount", null))) .minThreadCount(Optional.ofNullable(configurationFile.getInteger("minThreadCount", null))) .password(Optional.ofNullable(configurationFile.getString("password", null))) + .readOnlyPassword(Optional.ofNullable(configurationFile.getString("password.readonly", null))) + .noDeletePassword(Optional.ofNullable(configurationFile.getString("password.nodelete", null))) .build(); } catch (FileNotFoundException e) { LOGGER.info("No webadmin.properties file. Disabling WebAdmin interface."); diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java index 820a8cc826..1a6bc158b6 100644 --- a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java +++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/WebAdminConfiguration.java @@ -58,6 +58,8 @@ public class WebAdminConfiguration { private Optional<String> urlCORSOrigin = Optional.empty(); private Optional<String> host = Optional.empty(); private Optional<String> password = Optional.empty(); + private Optional<String> readOnlyPassword = Optional.empty(); + private Optional<String> noDeletePassword = Optional.empty(); private ImmutableList.Builder<String> additionalRoutes = ImmutableList.builder(); private Optional<String> jwtPublicKey = Optional.empty(); private Optional<Integer> maxThreadCount = Optional.empty(); @@ -134,6 +136,26 @@ public class WebAdminConfiguration { return this; } + public Builder readOnlyPassword(String readOnlyPassword) { + this.readOnlyPassword = Optional.ofNullable(readOnlyPassword); + return this; + } + + public Builder readOnlyPassword(Optional<String> readOnlyPassword) { + this.readOnlyPassword = readOnlyPassword; + return this; + } + + public Builder noDeletePassword(String noDeletePassword) { + this.noDeletePassword = Optional.ofNullable(noDeletePassword); + return this; + } + + public Builder noDeletePassword(Optional<String> noDeletePassword) { + this.noDeletePassword = noDeletePassword; + return this; + } + public Builder additionalRoute(String additionalRoute) { this.additionalRoutes.add(additionalRoute); return this; @@ -167,6 +189,8 @@ public class WebAdminConfiguration { additionalRoutes.build(), jwtPublicKey, password, + readOnlyPassword, + noDeletePassword, maxThreadCount, minThreadCount); } @@ -181,12 +205,16 @@ public class WebAdminConfiguration { private final List<String> additionalRoutes; private final Optional<String> jwtPublicKey; private final Optional<String> password; + private final Optional<String> readOnlyPassword; + private final Optional<String> noDeletePassword; private final Optional<Integer> maxThreadCount; private final Optional<Integer> minThreadCount; @VisibleForTesting WebAdminConfiguration(boolean enabled, Optional<PortSupplier> port, Optional<TlsConfiguration> tlsConfiguration, - boolean enableCORS, String urlCORSOrigin, String host, List<String> additionalRoutes, Optional<String> jwtPublicKey, Optional<String> password, Optional<Integer> maxThreadCount, Optional<Integer> minThreadCount) { + boolean enableCORS, String urlCORSOrigin, String host, List<String> additionalRoutes, + Optional<String> jwtPublicKey, Optional<String> password, Optional<String> readOnlyPassword, + Optional<String> noDeletePassword, Optional<Integer> maxThreadCount, Optional<Integer> minThreadCount) { this.enabled = enabled; this.port = port; this.tlsConfiguration = tlsConfiguration; @@ -196,6 +224,8 @@ public class WebAdminConfiguration { this.additionalRoutes = additionalRoutes; this.jwtPublicKey = jwtPublicKey; this.password = password; + this.readOnlyPassword = readOnlyPassword; + this.noDeletePassword = noDeletePassword; this.maxThreadCount = maxThreadCount; this.minThreadCount = minThreadCount; } @@ -248,6 +278,14 @@ public class WebAdminConfiguration { return password; } + public Optional<String> getReadOnlyPassword() { + return readOnlyPassword; + } + + public Optional<String> getNoDeletePassword() { + return noDeletePassword; + } + @Override public final boolean equals(Object o) { if (o instanceof WebAdminConfiguration) { @@ -261,6 +299,8 @@ public class WebAdminConfiguration { && Objects.equals(this.urlCORSOrigin, that.urlCORSOrigin) && Objects.equals(this.host, that.host) && Objects.equals(this.password, that.password) + && Objects.equals(this.readOnlyPassword, that.readOnlyPassword) + && Objects.equals(this.noDeletePassword, that.noDeletePassword) && Objects.equals(this.additionalRoutes, that.additionalRoutes) && Objects.equals(this.minThreadCount, that.minThreadCount) && Objects.equals(this.maxThreadCount, that.maxThreadCount); @@ -270,6 +310,7 @@ public class WebAdminConfiguration { @Override public final int hashCode() { - return Objects.hash(enabled, port, tlsConfiguration, enableCORS, jwtPublicKey, urlCORSOrigin, host, additionalRoutes, minThreadCount, maxThreadCount, password); + return Objects.hash(enabled, port, tlsConfiguration, enableCORS, jwtPublicKey, urlCORSOrigin, host, + password, readOnlyPassword, noDeletePassword, additionalRoutes, minThreadCount, maxThreadCount); } } diff --git a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java index 3b390f20fe..b8736c9061 100644 --- a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java +++ b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/WebAdminConfigurationTest.java @@ -22,6 +22,8 @@ package org.apache.james.webadmin; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.util.Optional; + import org.junit.jupiter.api.Test; import nl.jqno.equalsverifier.EqualsVerifier; @@ -190,6 +192,80 @@ class WebAdminConfigurationTest { .isEqualTo(host); } + @Test + void builderShouldAcceptReadOnlyPassword() { + String password = "readonly123"; + assertThat( + WebAdminConfiguration.builder() + .enabled() + .port(PORT) + .readOnlyPassword(password) + .build()) + .extracting(WebAdminConfiguration::getReadOnlyPassword) + .isEqualTo(Optional.of(password)); + } + + @Test + void builderShouldAcceptReadOnlyPasswordAsOptional() { + Optional<String> password = Optional.of("readonly456"); + assertThat( + WebAdminConfiguration.builder() + .enabled() + .port(PORT) + .readOnlyPassword(password) + .build()) + .extracting(WebAdminConfiguration::getReadOnlyPassword) + .isEqualTo(password); + } + + @Test + void builderShouldReturnEmptyReadOnlyPasswordByDefault() { + assertThat( + WebAdminConfiguration.builder() + .enabled() + .port(PORT) + .build()) + .extracting(WebAdminConfiguration::getReadOnlyPassword) + .isEqualTo(Optional.empty()); + } + + @Test + void builderShouldAcceptNoDeletePassword() { + String password = "nodelete123"; + assertThat( + WebAdminConfiguration.builder() + .enabled() + .port(PORT) + .noDeletePassword(password) + .build()) + .extracting(WebAdminConfiguration::getNoDeletePassword) + .isEqualTo(Optional.of(password)); + } + + @Test + void builderShouldAcceptNoDeletePasswordAsOptional() { + Optional<String> password = Optional.of("nodelete456"); + assertThat( + WebAdminConfiguration.builder() + .enabled() + .port(PORT) + .noDeletePassword(password) + .build()) + .extracting(WebAdminConfiguration::getNoDeletePassword) + .isEqualTo(password); + } + + @Test + void builderShouldReturnEmptyNoDeletePasswordByDefault() { + assertThat( + WebAdminConfiguration.builder() + .enabled() + .port(PORT) + .build()) + .extracting(WebAdminConfiguration::getNoDeletePassword) + .isEqualTo(Optional.empty()); + } + @Test void shouldMatchBeanContract() { EqualsVerifier.forClass(WebAdminConfiguration.class).verify(); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
