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
The following commit(s) were added to refs/heads/master by this push:
new 62f45bdfa3 JAMES-3680 XUserAuthenticationStrategy support list secret
62f45bdfa3 is described below
commit 62f45bdfa30731ca661f5ae74e3a344497ba48b9
Author: TungTV <[email protected]>
AuthorDate: Thu Oct 17 12:45:00 2024 +0700
JAMES-3680 XUserAuthenticationStrategy support list secret
---
docs/modules/servers/partials/configure/jmap.adoc | 2 +-
...eJmapRFC8621AuthenticationStrategyContract.java | 26 ++++++++++++++++++----
.../jmap/http/XUserAuthenticationStrategy.java | 17 +++++++++-----
src/site/xdoc/server/config-jmap.xml | 2 +-
4 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/docs/modules/servers/partials/configure/jmap.adoc
b/docs/modules/servers/partials/configure/jmap.adoc
index 87bcfa21fb..c5f697c53f 100644
--- a/docs/modules/servers/partials/configure/jmap.adoc
+++ b/docs/modules/servers/partials/configure/jmap.adoc
@@ -101,7 +101,7 @@ This allows to prevent users from using some specific JMAP
extensions.
| Optional, default value is 500. The max number of items for /set methods.
| authentication.strategy.rfc8621.xUser.secret
-| Optional. Disabled by default. Secret-value used to validate the
X-User-Secret header when using the XUserAuthenticationStrategy. Use of this
configuration property is highly advised.
+| Optional. List[String] with delimiter ",". Disabled by default. Secret-value
used to validate the X-User-Secret header when using the
XUserAuthenticationStrategy. Use of this configuration property is highly
advised.
|===
diff --git
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/custom/authentication/strategy/ModularizeJmapRFC8621AuthenticationStrategyContract.java
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/custom/authentication/strategy/ModularizeJmapRFC8621AuthenticationStrategyContract.java
index 5dd126da9a..a86d088a59 100644
---
a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/custom/authentication/strategy/ModularizeJmapRFC8621AuthenticationStrategyContract.java
+++
b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/custom/authentication/strategy/ModularizeJmapRFC8621AuthenticationStrategyContract.java
@@ -43,6 +43,7 @@ import static org.hamcrest.Matchers.equalTo;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.ThreadLocalRandom;
import org.apache.james.GuiceJamesServer;
import org.apache.james.jmap.JmapGuiceProbe;
@@ -243,7 +244,7 @@ public abstract class
ModularizeJmapRFC8621AuthenticationStrategyContract {
public void
givenXUserStrategyWhenMissingXUserSecretHeaderShouldFail(GuiceJamesServer
server) throws Throwable {
// given a server with XUserAuthenticationStrategy
// The XUserAuthenticationStrategy is configured with a secret:
"secret1"
- setupJamesServerWithXUserStrategy(server, Optional.of("secret1"));
+ setupJamesServerWithXUserStrategy(server,
Optional.of(List.of("secret1")));
// when a request is made without the X-User-Secret header
// then the request should fail with a 401 status code
@@ -262,7 +263,7 @@ public abstract class
ModularizeJmapRFC8621AuthenticationStrategyContract {
public void
givenXUserStrategyWhenInvalidateXUserSecretHeaderShouldFail(GuiceJamesServer
server) throws Throwable {
// given a server with XUserAuthenticationStrategy
// The XUserAuthenticationStrategy is configured with a secret:
"secret1"
- setupJamesServerWithXUserStrategy(server, Optional.of("secret1"));
+ setupJamesServerWithXUserStrategy(server,
Optional.of(List.of("secret1")));
// when a request is made with an invalid X-User-Secret header
// then the request should fail with a 401 status code
@@ -283,7 +284,7 @@ public abstract class
ModularizeJmapRFC8621AuthenticationStrategyContract {
// given a server with XUserAuthenticationStrategy
// The XUserAuthenticationStrategy is configured with a secret:
"secret1"
String secret = "secret1";
- setupJamesServerWithXUserStrategy(server, Optional.of(secret));
+ setupJamesServerWithXUserStrategy(server,
Optional.of(List.of(secret)));
// when a request is made with an invalid X-User-Secret header
// then the request should fail with a 401 status code
@@ -314,7 +315,24 @@ public abstract class
ModularizeJmapRFC8621AuthenticationStrategyContract {
.body("username", equalTo(BOB().asString()));
}
- private void setupJamesServerWithXUserStrategy(GuiceJamesServer server,
Optional<String> xUserSecret) throws Exception {
+ @Test
+ public void givenXUserStrategySupportListSecret(GuiceJamesServer server)
throws Throwable {
+ List<String> validatedSecretList = List.of("secret1", "secret2",
"secret3");
+ setupJamesServerWithXUserStrategy(server,
Optional.of(validatedSecretList));
+
+ // when a request is made with an invalid X-User-Secret header
+ // then the request should fail with a 401 status code
+ given()
+ .header(new Header("X-User", BOB().asString()))
+ .header(new Header("X-User-Secret",
validatedSecretList.get(ThreadLocalRandom.current().nextInt(3))))
+ .when()
+ .get("/session")
+ .then()
+ .statusCode(SC_OK)
+ .body("username", equalTo(BOB().asString()));
+ }
+
+ private void setupJamesServerWithXUserStrategy(GuiceJamesServer server,
Optional<List<String>> xUserSecret) throws Exception {
jmapServer = server
.overrideWith(new AbstractModule() {
@Provides
diff --git
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/http/XUserAuthenticationStrategy.java
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/http/XUserAuthenticationStrategy.java
index 7de77df0a1..d357e3edc7 100644
---
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/http/XUserAuthenticationStrategy.java
+++
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/http/XUserAuthenticationStrategy.java
@@ -20,6 +20,7 @@
package org.apache.james.jmap.http;
import java.io.FileNotFoundException;
+import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@@ -35,6 +36,7 @@ import org.apache.james.utils.PropertiesProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import reactor.core.publisher.Mono;
@@ -50,12 +52,15 @@ public class XUserAuthenticationStrategy implements
AuthenticationStrategy {
AuthenticationScheme.of("XUserHeader"),
ImmutableMap.of());
- private static Optional<String>
extractXUserSecretFromConfig(PropertiesProvider propertiesProvider) throws
ConfigurationException {
+ private static Optional<List<String>>
extractXUserSecretFromConfig(PropertiesProvider propertiesProvider) throws
ConfigurationException {
try {
return
Optional.ofNullable(propertiesProvider.getConfiguration("jmap"))
- .map(config ->
config.getString(AUTHENTICATION_STRATEGY_XUSER_SECRET, null));
+ .map(config -> config.getList(String.class,
AUTHENTICATION_STRATEGY_XUSER_SECRET, null))
+ .map(list -> {
+ Preconditions.checkArgument(!list.isEmpty(),
AUTHENTICATION_STRATEGY_XUSER_SECRET + " must not be empty");
+ return list;
+ });
} catch (FileNotFoundException e) {
- LOGGER.warn("");
return Optional.empty();
}
}
@@ -73,7 +78,7 @@ public class XUserAuthenticationStrategy implements
AuthenticationStrategy {
public XUserAuthenticationStrategy(UsersRepository usersRepository,
MailboxManager mailboxManager,
- Optional<String> xUserSecret) {
+ Optional<List<String>> xUserSecret) {
this.usersRepository = usersRepository;
this.mailboxManager = mailboxManager;
this.usernameExtractor = xUserSecret
@@ -110,10 +115,10 @@ public class XUserAuthenticationStrategy implements
AuthenticationStrategy {
.map(Username::of);
}
- private Function<HttpServerRequest, Optional<Username>>
createUsernameExtractorWithSecretValidation(String secret) {
+ private Function<HttpServerRequest, Optional<Username>>
createUsernameExtractorWithSecretValidation(List<String> validatedSecretList) {
return httpRequest ->
createUsernameExtractorWithoutSecretValidation().apply(httpRequest)
.filter(username ->
Optional.ofNullable(httpRequest.requestHeaders().get(X_USER_SECRET_HEADER_NAME))
- .map(secret::equals)
+ .map(validatedSecretList::contains)
.orElse(false));
}
}
diff --git a/src/site/xdoc/server/config-jmap.xml
b/src/site/xdoc/server/config-jmap.xml
index e1b6c5cf71..23cea6c482 100644
--- a/src/site/xdoc/server/config-jmap.xml
+++ b/src/site/xdoc/server/config-jmap.xml
@@ -143,7 +143,7 @@
<dd>Optional, default value is 500. The max number of
items for /set methods.</dd>
<dt><string>authentication.strategy.rfc8621.xUser.secret</string></dt>
- <dd>Optional. Disabled by default. Secret-value used to
validate the X-User-Secret header when using the XUserAuthenticationStrategy.
Use of this configuration property is highly advised.</dd>
+ <dd>Optional, List[String] with delimiter ",". Disabled by
default. Secret-value used to validate the X-User-Secret header when using the
XUserAuthenticationStrategy. Use of this configuration property is highly
advised.</dd>
</dl>
</subsection>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]