This is an automated email from the ASF dual-hosted git repository.

chibenwa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git


The following commit(s) were added to refs/heads/master by this push:
     new 0cd766633a JAMES-4201 Remove the `password.nodelete` webadmin access 
level
0cd766633a is described below

commit 0cd766633a23a4125f1275f1691e6712087b3f5c
Author: Benoit TELLIER <[email protected]>
AuthorDate: Wed Sep 2 13:37:24 2026 +0200

    JAMES-4201 Remove the `password.nodelete` webadmin access level
    
    `password.nodelete` was introduced alongside `password.readonly` and never
    released. It promised that such a credential "can read and create/modify 
data
    but cannot delete", but the filter only compares the literal HTTP method, 
while
    WebAdmin models plenty of destructive operations as POST or PUT:
    
     - `POST /users/{username}?action=deleteData` and
       `POST /domains/{domainName}?action=deleteData` erase user data through a 
task,
     - `PUT /users/{username}` resets the password of an existing account, 
which is a
       full account takeover,
     - `PUT /domains/{domain}/aliases/{alias}` and the forward routes reroute 
mail.
    
    Making the filter action-aware would only paper over this: on an 
administration
    API where creating and updating is as destructive as deleting, "everything 
but
    the DELETE verb" cannot be a privilege separation, merely a guard-rail 
against
    mistyped `curl` commands - one that reads as a security boundary and is
    documented as one.
    
    So drop the level rather than keep a boundary we cannot honour.
---
 CHANGELOG.md                                       |  2 +-
 .../servers/partials/configure/webadmin.adoc       | 32 +++++-----------
 .../sample-configuration/webadmin.properties       |  4 --
 .../sample-configuration/webadmin.properties       |  4 --
 .../sample-configuration/webadmin.properties       |  4 --
 .../sample-configuration/webadmin.properties       |  4 --
 .../sample-configuration/webadmin.properties       |  4 --
 .../sample-configuration/webadmin.properties       |  4 --
 .../sample-configuration/webadmin.properties       |  4 --
 .../james/modules/server/WebAdminServerModule.java |  5 +--
 .../james/webadmin/WebAdminConfiguration.java      | 25 ++-----------
 .../webadmin/authentication/PasswordFilter.java    | 12 +-----
 .../james/webadmin/WebAdminConfigurationTest.java  | 37 -------------------
 .../authentication/PasswordFilterTest.java         | 43 +---------------------
 14 files changed, 17 insertions(+), 167 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2fddc16c72..743a141100 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,7 +15,7 @@ The format is based on [Keep a 
Changelog](http://keepachangelog.com/en/1.0.0/)
 ### Security
 
  - JAMES-4193 Correct BoringSSL TLS 1.3 cipher suite sanitizing that led to 
disabled TLS 1.3 (#3029)
- - JAMES-4201 Implement granular password access control in webadmin 
(`password.readonly` and `password.nodelete`)
+ - JAMES-4201 Implement a read-only password access level in webadmin 
(`password.readonly`)
  - Webadmin `password.generate`: generate a random password upon start up when 
none is configured, and log it.
  **Breaking change**: this defaults to `true`, thus webadmin is no longer 
unauthenticated out of the box, existing
  deployments included. Set `password.generate=false` in `webadmin.properties` 
to opt back into an unauthenticated
diff --git a/docs/modules/servers/partials/configure/webadmin.adoc 
b/docs/modules/servers/partials/configure/webadmin.adoc
index c0f7f2a6da..5fb20c33a9 100644
--- a/docs/modules/servers/partials/configure/webadmin.adoc
+++ b/docs/modules/servers/partials/configure/webadmin.adoc
@@ -106,29 +106,15 @@ DELETE /users
 PUT /mailboxes
 ....
 
-| password.nodelete
-| Configures passwords that allow all operations except DELETE.
-These passwords can read and create/modify data but cannot delete.
-Multiple passwords can be configured as a comma-separated list.
-
-....
-password.nodelete=ccc,ddd
-....
-
-Requests with these passwords will be allowed for:
-
-....
-GET /domains
-POST /users
-PUT /mailboxes
-....
-+
-But denied for:
-+
-....
-DELETE /domains
-DELETE /users
-....
+Note that this is the only reduced privilege level WebAdmin offers: read-only, 
or full administrative access.
+Any password configured through `password` grants the full WebAdmin surface, 
which includes resetting the
+credentials of arbitrary users, rerouting their mail and deleting their data.
+
+WebAdmin has no notion of administrator identity, and models several 
destructive operations as `POST` task
+actions rather than as `DELETE` requests, so no HTTP verb based scheme can 
express a meaningful partial
+privilege. Deployments needing per-operation, per-domain or per-administrator 
delegation should place an
+authenticating reverse proxy in front of WebAdmin, which can tie an 
authenticated identity to the set of
+routes - query parameters included - it is allowed to call.
 
 | jwt.enable
 | Allow JSON Web Token as an authentication mechanism (default: false)
diff --git 
a/server/apps/distributed-app/sample-configuration/webadmin.properties 
b/server/apps/distributed-app/sample-configuration/webadmin.properties
index 27bc60395c..d8f1632021 100644
--- a/server/apps/distributed-app/sample-configuration/webadmin.properties
+++ b/server/apps/distributed-app/sample-configuration/webadmin.properties
@@ -68,7 +68,3 @@ password.generate=true
 # Read-only passwords - only allow GET requests
 # These passwords can only perform read operations
 #password.readonly=aaa,bbb
-
-# No-delete passwords - allow all operations except DELETE
-# These passwords can perform read and write operations but not delete
-#password.nodelete=ccc,ddd
\ No newline at end of file
diff --git 
a/server/apps/distributed-pop3-app/sample-configuration/webadmin.properties 
b/server/apps/distributed-pop3-app/sample-configuration/webadmin.properties
index 27bc60395c..d8f1632021 100644
--- a/server/apps/distributed-pop3-app/sample-configuration/webadmin.properties
+++ b/server/apps/distributed-pop3-app/sample-configuration/webadmin.properties
@@ -68,7 +68,3 @@ password.generate=true
 # Read-only passwords - only allow GET requests
 # These passwords can only perform read operations
 #password.readonly=aaa,bbb
-
-# No-delete passwords - allow all operations except DELETE
-# These passwords can perform read and write operations but not delete
-#password.nodelete=ccc,ddd
\ No newline at end of file
diff --git a/server/apps/jpa-app/sample-configuration/webadmin.properties 
b/server/apps/jpa-app/sample-configuration/webadmin.properties
index c2a336b1e0..d280a9e544 100644
--- a/server/apps/jpa-app/sample-configuration/webadmin.properties
+++ b/server/apps/jpa-app/sample-configuration/webadmin.properties
@@ -62,7 +62,3 @@ password.generate=true
 # Read-only passwords - only allow GET requests
 # These passwords can only perform read operations
 #password.readonly=aaa,bbb
-
-# No-delete passwords - allow all operations except DELETE
-# These passwords can perform read and write operations but not delete
-#password.nodelete=ccc,ddd
\ No newline at end of file
diff --git a/server/apps/jpa-smtp-app/sample-configuration/webadmin.properties 
b/server/apps/jpa-smtp-app/sample-configuration/webadmin.properties
index c2a336b1e0..d280a9e544 100644
--- a/server/apps/jpa-smtp-app/sample-configuration/webadmin.properties
+++ b/server/apps/jpa-smtp-app/sample-configuration/webadmin.properties
@@ -62,7 +62,3 @@ password.generate=true
 # Read-only passwords - only allow GET requests
 # These passwords can only perform read operations
 #password.readonly=aaa,bbb
-
-# No-delete passwords - allow all operations except DELETE
-# These passwords can perform read and write operations but not delete
-#password.nodelete=ccc,ddd
\ No newline at end of file
diff --git a/server/apps/memory-app/sample-configuration/webadmin.properties 
b/server/apps/memory-app/sample-configuration/webadmin.properties
index a451aca7b8..1898d6c4b3 100644
--- a/server/apps/memory-app/sample-configuration/webadmin.properties
+++ b/server/apps/memory-app/sample-configuration/webadmin.properties
@@ -69,7 +69,3 @@ password.generate=true
 # Read-only passwords - only allow GET requests
 # These passwords can only perform read operations
 #password.readonly=aaa,bbb
-
-# No-delete passwords - allow all operations except DELETE
-# These passwords can perform read and write operations but not delete
-#password.nodelete=ccc,ddd
\ No newline at end of file
diff --git a/server/apps/postgres-app/sample-configuration/webadmin.properties 
b/server/apps/postgres-app/sample-configuration/webadmin.properties
index c2a336b1e0..d280a9e544 100644
--- a/server/apps/postgres-app/sample-configuration/webadmin.properties
+++ b/server/apps/postgres-app/sample-configuration/webadmin.properties
@@ -62,7 +62,3 @@ password.generate=true
 # Read-only passwords - only allow GET requests
 # These passwords can only perform read operations
 #password.readonly=aaa,bbb
-
-# No-delete passwords - allow all operations except DELETE
-# These passwords can perform read and write operations but not delete
-#password.nodelete=ccc,ddd
\ No newline at end of file
diff --git 
a/server/apps/scaling-pulsar-smtp/sample-configuration/webadmin.properties 
b/server/apps/scaling-pulsar-smtp/sample-configuration/webadmin.properties
index 986133dfa5..e5ce733c35 100644
--- a/server/apps/scaling-pulsar-smtp/sample-configuration/webadmin.properties
+++ b/server/apps/scaling-pulsar-smtp/sample-configuration/webadmin.properties
@@ -62,7 +62,3 @@ password.generate=true
 # Read-only passwords - only allow GET requests
 # These passwords can only perform read operations
 #password.readonly=aaa,bbb
-
-# No-delete passwords - allow all operations except DELETE
-# These passwords can perform read and write operations but not delete
-#password.nodelete=ccc,ddd
\ No newline at end of file
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 838b412417..e11bd08a01 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
@@ -172,7 +172,6 @@ public class WebAdminServerModule extends AbstractModule {
                 
.minThreadCount(Optional.ofNullable(configurationFile.getInteger("minThreadCount",
 null)))
                 .password(password(configurationFile, webAdminEnabled, 
passwordGenerationDefault))
                 
.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.");
@@ -241,8 +240,7 @@ public class WebAdminServerModule extends AbstractModule {
             }
             if (isPasswordPresent(webAdminConfiguration)) {
                 return new PasswordFilter(webAdminConfiguration.getPassword(),
-                    webAdminConfiguration.getReadOnlyPassword(),
-                    webAdminConfiguration.getNoDeletePassword());
+                    webAdminConfiguration.getReadOnlyPassword());
             }
             return new NoAuthenticationFilter();
         } catch (FileNotFoundException e) {
@@ -252,7 +250,6 @@ public class WebAdminServerModule extends AbstractModule {
 
     private boolean isPasswordPresent(WebAdminConfiguration 
webAdminConfiguration) {
         return webAdminConfiguration.getPassword().isPresent()
-            || webAdminConfiguration.getNoDeletePassword().isPresent()
             || webAdminConfiguration.getReadOnlyPassword().isPresent();
     }
 
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 1a6bc158b6..706a9f10eb 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
@@ -59,7 +59,6 @@ public class WebAdminConfiguration {
         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();
@@ -146,16 +145,6 @@ public class WebAdminConfiguration {
             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;
@@ -190,7 +179,6 @@ public class WebAdminConfiguration {
                 jwtPublicKey,
                 password,
                 readOnlyPassword,
-                noDeletePassword,
                 maxThreadCount,
                 minThreadCount);
         }
@@ -206,15 +194,14 @@ public class WebAdminConfiguration {
     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<String> readOnlyPassword, 
-                          Optional<String> noDeletePassword, Optional<Integer> 
maxThreadCount, Optional<Integer> minThreadCount) {
+                          Optional<String> jwtPublicKey, Optional<String> 
password, Optional<String> readOnlyPassword,
+                          Optional<Integer> maxThreadCount, Optional<Integer> 
minThreadCount) {
         this.enabled = enabled;
         this.port = port;
         this.tlsConfiguration = tlsConfiguration;
@@ -225,7 +212,6 @@ public class WebAdminConfiguration {
         this.jwtPublicKey = jwtPublicKey;
         this.password = password;
         this.readOnlyPassword = readOnlyPassword;
-        this.noDeletePassword = noDeletePassword;
         this.maxThreadCount = maxThreadCount;
         this.minThreadCount = minThreadCount;
     }
@@ -282,10 +268,6 @@ public class WebAdminConfiguration {
         return readOnlyPassword;
     }
 
-    public Optional<String> getNoDeletePassword() {
-        return noDeletePassword;
-    }
-
     @Override
     public final boolean equals(Object o) {
         if (o instanceof WebAdminConfiguration) {
@@ -300,7 +282,6 @@ public class WebAdminConfiguration {
                 && 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);
@@ -311,6 +292,6 @@ public class WebAdminConfiguration {
     @Override
     public final int hashCode() {
         return Objects.hash(enabled, port, tlsConfiguration, enableCORS, 
jwtPublicKey, urlCORSOrigin, host, 
-            password, readOnlyPassword, noDeletePassword, additionalRoutes, 
minThreadCount, maxThreadCount);
+            password, readOnlyPassword, additionalRoutes, minThreadCount, 
maxThreadCount);
     }
 }
diff --git 
a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/PasswordFilter.java
 
b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/PasswordFilter.java
index 6c46db42ab..bba959fe99 100644
--- 
a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/PasswordFilter.java
+++ 
b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/authentication/PasswordFilter.java
@@ -42,22 +42,18 @@ public class PasswordFilter implements AuthenticationFilter 
{
 
     private static final String GET_METHOD = "GET";
     private static final String HEAD_METHOD = "HEAD";
-    private static final String DELETE_METHOD = "DELETE";
 
     private final Optional<List<String>> passwords;
     private final Optional<List<String>> readOnlyPasswords;
-    private final Optional<List<String>> noDeletePasswords;
 
     /**
      * @param passwordString optional comma-separated list of full-access 
passwords
      * @param readOnlyPasswordString optional comma-separated list of 
read-only passwords
-     * @param noDeletePasswordString optional comma-separated list of 
no-delete passwords
      */
     @Inject
-    public PasswordFilter(Optional<String> passwordString, Optional<String> 
readOnlyPasswordString, Optional<String> noDeletePasswordString) {
+    public PasswordFilter(Optional<String> passwordString, Optional<String> 
readOnlyPasswordString) {
         this.passwords = splitOptionalPasswords(passwordString);
         this.readOnlyPasswords = 
splitOptionalPasswords(readOnlyPasswordString);
-        this.noDeletePasswords = 
splitOptionalPasswords(noDeletePasswordString);
     }
 
     private Optional<List<String>> splitOptionalPasswords(Optional<String> 
optionalPasswordString) {
@@ -73,7 +69,6 @@ public class PasswordFilter implements AuthenticationFilter {
 
     private enum AccessLevel {
         FULL,
-        NO_DELETE,
         READ_ONLY,
         NONE
     }
@@ -82,9 +77,6 @@ public class PasswordFilter implements AuthenticationFilter {
         if (passwords.isPresent() && passwords.get().contains(password)) {
             return AccessLevel.FULL;
         }
-        if (noDeletePasswords.isPresent() && 
noDeletePasswords.get().contains(password)) {
-            return AccessLevel.NO_DELETE;
-        }
         if (readOnlyPasswords.isPresent() && 
readOnlyPasswords.get().contains(password)) {
             return AccessLevel.READ_ONLY;
         }
@@ -95,8 +87,6 @@ public class PasswordFilter implements AuthenticationFilter {
         switch (accessLevel) {
             case FULL:
                 return true;
-            case NO_DELETE:
-                return !httpMethod.equals(DELETE_METHOD);
             case READ_ONLY:
                 return httpMethod.equals(GET_METHOD) || 
httpMethod.equals(HEAD_METHOD);
             case NONE:
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 b8736c9061..9345df4058 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
@@ -229,43 +229,6 @@ class WebAdminConfigurationTest {
             .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();
diff --git 
a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/authentication/PasswordFilterTest.java
 
b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/authentication/PasswordFilterTest.java
index b2295b44df..26f7c59b18 100644
--- 
a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/authentication/PasswordFilterTest.java
+++ 
b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/authentication/PasswordFilterTest.java
@@ -40,7 +40,7 @@ class PasswordFilterTest {
 
     @BeforeEach
     void setUp() {
-        testee = new PasswordFilter(Optional.of("abc,def"), 
Optional.of("readonly1,readonly2"), Optional.of("nodelete1,nodelete2"));
+        testee = new PasswordFilter(Optional.of("abc,def"), 
Optional.of("readonly1,readonly2"));
     }
 
     @Test
@@ -172,45 +172,6 @@ class PasswordFilterTest {
         testee.handle(request, mock(Response.class));
     }
 
-    @Test
-    void handleShouldAcceptValidNoDeletePasswordOnGet() throws Exception {
-        Request request = mock(Request.class);
-        when(request.requestMethod()).thenReturn("GET");
-        when(request.headers("Password")).thenReturn("nodelete1");
-
-        testee.handle(request, mock(Response.class));
-    }
-
-    @Test
-    void handleShouldAcceptValidNoDeletePasswordOnPost() throws Exception {
-        Request request = mock(Request.class);
-        when(request.requestMethod()).thenReturn("POST");
-        when(request.headers("Password")).thenReturn("nodelete1");
-
-        testee.handle(request, mock(Response.class));
-    }
-
-    @Test
-    void handleShouldRejectNoDeletePasswordOnDelete() {
-        Request request = mock(Request.class);
-        when(request.requestMethod()).thenReturn("DELETE");
-        when(request.headers("Password")).thenReturn("nodelete1");
-
-        assertThatThrownBy(() -> testee.handle(request, mock(Response.class)))
-            .isInstanceOf(HaltException.class)
-            .extracting(e -> HaltException.class.cast(e).statusCode())
-            .isEqualTo(403);
-    }
-
-    @Test
-    void handleShouldAcceptValidNoDeletePasswordOnPut() throws Exception {
-        Request request = mock(Request.class);
-        when(request.requestMethod()).thenReturn("PUT");
-        when(request.headers("Password")).thenReturn("nodelete2");
-
-        testee.handle(request, mock(Response.class));
-    }
-
     @Test
     void handleShouldAcceptFullPasswordOnDelete() throws Exception {
         Request request = mock(Request.class);
@@ -231,7 +192,7 @@ class PasswordFilterTest {
 
     @Test
     void handleShouldRejectWhenNoConfiguredPasswords() {
-        PasswordFilter filterWithNulls = new PasswordFilter(Optional.empty(), 
Optional.empty(), Optional.empty());
+        PasswordFilter filterWithNulls = new PasswordFilter(Optional.empty(), 
Optional.empty());
         Request request = mock(Request.class);
         when(request.requestMethod()).thenReturn("GET");
         when(request.headers("Password")).thenReturn("anypassword");


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to