You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by rc...@apache.org on 2020/06/05 03:26:01 UTC
[james-project] 04/05: JAMES-3093 Add JWT Authentication,
integration test for JMAP RFC 8621
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 c3965277428a9ffdef6bdf997163a66290d7a139
Author: duc91 <du...@gmail.com>
AuthorDate: Fri May 22 11:51:44 2020 +0700
JAMES-3093 Add JWT Authentication, integration test for JMAP RFC 8621
---
.../james/jmap/draft/DraftMethodsModule.java | 2 +-
.../james/jmap/rfc8621/RFC8621MethodsModule.java | 10 +-
.../apache/james/jmap/http/AuthenticatorTest.java | 2 +-
.../jmap/http/JWTAuthenticationStrategyTest.java | 3 +-
.../DistributedBasicAuthenticationTest.java | 4 +-
.../distributed/DistributedEchoMethodTest.java | 1 -
....java => DistributedJWTAuthenticationTest.java} | 6 +-
...act.scala => BasicAuthenticationContract.scala} | 46 ++-------
.../james/jmap/rfc8621/contract/Fixture.scala | 35 ++++++-
.../contract/JWTAuthenticationContract.scala | 107 +++++++++++++++++++++
.../rfc8621/memory/MemoryAuthenticationTest.java | 4 +-
server/protocols/jmap-rfc-8621/pom.xml | 4 +
server/protocols/jmap/pom.xml | 18 +++-
.../MailboxSessionCreationException.java | 2 +-
.../james/jmap/jwt}/JWTAuthenticationStrategy.java | 10 +-
15 files changed, 192 insertions(+), 62 deletions(-)
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/DraftMethodsModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/DraftMethodsModule.java
index 72488fd..d95d95c 100644
--- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/DraftMethodsModule.java
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/DraftMethodsModule.java
@@ -46,8 +46,8 @@ import org.apache.james.jmap.draft.methods.SetVacationResponseMethod;
import org.apache.james.jmap.http.AccessTokenAuthenticationStrategy;
import org.apache.james.jmap.http.Authenticator;
import org.apache.james.jmap.http.InjectionKeys;
-import org.apache.james.jmap.http.JWTAuthenticationStrategy;
import org.apache.james.jmap.http.QueryParameterAccessTokenAuthenticationStrategy;
+import org.apache.james.jmap.jwt.JWTAuthenticationStrategy;
import org.apache.james.metrics.api.MetricFactory;
import com.google.inject.AbstractModule;
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/rfc8621/RFC8621MethodsModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/rfc8621/RFC8621MethodsModule.java
index adffa45..f085137 100644
--- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/rfc8621/RFC8621MethodsModule.java
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/rfc8621/RFC8621MethodsModule.java
@@ -26,6 +26,7 @@ import org.apache.james.jmap.http.Authenticator;
import org.apache.james.jmap.http.BasicAuthenticationStrategy;
import org.apache.james.jmap.http.rfc8621.InjectionKeys;
import org.apache.james.jmap.json.Serializer;
+import org.apache.james.jmap.jwt.JWTAuthenticationStrategy;
import org.apache.james.jmap.method.CoreEcho;
import org.apache.james.jmap.method.Method;
import org.apache.james.jmap.routes.JMAPApiRoutes;
@@ -57,7 +58,12 @@ public class RFC8621MethodsModule extends AbstractModule {
@Provides
@Singleton
@Named(InjectionKeys.RFC_8621)
- Authenticator provideAuthenticator(MetricFactory metricFactory, BasicAuthenticationStrategy basicAuthenticationStrategy) {
- return Authenticator.of(metricFactory, basicAuthenticationStrategy);
+ Authenticator provideAuthenticator(MetricFactory metricFactory,
+ BasicAuthenticationStrategy basicAuthenticationStrategy,
+ JWTAuthenticationStrategy jwtAuthenticationStrategy) {
+ return Authenticator.of(
+ metricFactory,
+ basicAuthenticationStrategy,
+ jwtAuthenticationStrategy);
}
}
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/AuthenticatorTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/AuthenticatorTest.java
index 59c3816..f009783 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/AuthenticatorTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/AuthenticatorTest.java
@@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.james.core.Username;
import org.apache.james.jmap.api.access.AccessToken;
import org.apache.james.jmap.api.access.AccessTokenRepository;
-import org.apache.james.jmap.draft.exceptions.MailboxSessionCreationException;
+import org.apache.james.jmap.exceptions.MailboxSessionCreationException;
import org.apache.james.jmap.exceptions.UnauthorizedException;
import org.apache.james.jmap.memory.access.MemoryAccessTokenRepository;
import org.apache.james.mailbox.MailboxSession;
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/JWTAuthenticationStrategyTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/JWTAuthenticationStrategyTest.java
index 49d5144..ac5169d 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/JWTAuthenticationStrategyTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/JWTAuthenticationStrategyTest.java
@@ -26,7 +26,8 @@ import static org.mockito.Mockito.when;
import org.apache.james.core.Username;
import org.apache.james.domainlist.api.DomainList;
-import org.apache.james.jmap.draft.exceptions.MailboxSessionCreationException;
+import org.apache.james.jmap.exceptions.MailboxSessionCreationException;
+import org.apache.james.jmap.jwt.JWTAuthenticationStrategy;
import org.apache.james.jwt.JwtTokenVerifier;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedBasicAuthenticationTest.java b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedBasicAuthenticationTest.java
index 1d7932b..d4f2151 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedBasicAuthenticationTest.java
+++ b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedBasicAuthenticationTest.java
@@ -26,14 +26,14 @@ import org.apache.james.DockerElasticSearchExtension;
import org.apache.james.GuiceJamesServer;
import org.apache.james.JamesServerBuilder;
import org.apache.james.JamesServerExtension;
-import org.apache.james.jmap.rfc8621.contract.AuthenticationContract;
+import org.apache.james.jmap.rfc8621.contract.BasicAuthenticationContract;
import org.apache.james.modules.AwsS3BlobStoreExtension;
import org.apache.james.modules.RabbitMQExtension;
import org.apache.james.modules.TestJMAPServerModule;
import org.apache.james.modules.blobstore.BlobStoreConfiguration;
import org.junit.jupiter.api.extension.RegisterExtension;
-public class DistributedBasicAuthenticationTest implements AuthenticationContract {
+public class DistributedBasicAuthenticationTest implements BasicAuthenticationContract {
@RegisterExtension
static JamesServerExtension testExtension = new JamesServerBuilder<CassandraRabbitMQJamesConfiguration>(tmpDir ->
CassandraRabbitMQJamesConfiguration.builder()
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEchoMethodTest.java b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEchoMethodTest.java
index c55787b..1e504db 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEchoMethodTest.java
+++ b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEchoMethodTest.java
@@ -23,7 +23,6 @@ import org.apache.james.CassandraExtension;
import org.apache.james.CassandraRabbitMQJamesConfiguration;
import org.apache.james.CassandraRabbitMQJamesServerMain;
import org.apache.james.DockerElasticSearchExtension;
-import org.apache.james.GuiceJamesServer;
import org.apache.james.JamesServerBuilder;
import org.apache.james.JamesServerExtension;
import org.apache.james.jmap.rfc8621.contract.EchoMethodContract;
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEchoMethodTest.java b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedJWTAuthenticationTest.java
similarity index 93%
copy from server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEchoMethodTest.java
copy to server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedJWTAuthenticationTest.java
index c55787b..0a8787b 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEchoMethodTest.java
+++ b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedJWTAuthenticationTest.java
@@ -23,18 +23,16 @@ import org.apache.james.CassandraExtension;
import org.apache.james.CassandraRabbitMQJamesConfiguration;
import org.apache.james.CassandraRabbitMQJamesServerMain;
import org.apache.james.DockerElasticSearchExtension;
-import org.apache.james.GuiceJamesServer;
import org.apache.james.JamesServerBuilder;
import org.apache.james.JamesServerExtension;
-import org.apache.james.jmap.rfc8621.contract.EchoMethodContract;
+import org.apache.james.jmap.rfc8621.contract.JWTAuthenticationContract;
import org.apache.james.modules.AwsS3BlobStoreExtension;
import org.apache.james.modules.RabbitMQExtension;
import org.apache.james.modules.TestJMAPServerModule;
import org.apache.james.modules.blobstore.BlobStoreConfiguration;
import org.junit.jupiter.api.extension.RegisterExtension;
-public class DistributedEchoMethodTest implements EchoMethodContract {
-
+public class DistributedJWTAuthenticationTest implements JWTAuthenticationContract {
@RegisterExtension
static JamesServerExtension testExtension = new JamesServerBuilder<CassandraRabbitMQJamesConfiguration>(tmpDir ->
CassandraRabbitMQJamesConfiguration.builder()
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/AuthenticationContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/BasicAuthenticationContract.scala
similarity index 68%
rename from server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/AuthenticationContract.scala
rename to server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/BasicAuthenticationContract.scala
index 6716c1a..f257bbf 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/AuthenticationContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/BasicAuthenticationContract.scala
@@ -1,44 +1,27 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you under the Apache License, Version 2.0 (the *
- * "License"); you may not use this file except in compliance *
- * with the License. You may obtain a copy of the License at *
- * *
- * http://www.apache.org/licenses/LICENSE-2.0 *
- * *
- * Unless required by applicable law or agreed to in writing, *
- * software distributed under the License is distributed on an *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
- * KIND, either express or implied. See the License for the *
- * specific language governing permissions and limitations *
- * under the License. *
- ****************************************************************/
-
package org.apache.james.jmap.rfc8621.contract
import java.nio.charset.StandardCharsets.UTF_8
import java.util.Base64
import io.netty.handler.codec.http.HttpHeaderNames.ACCEPT
-import io.restassured.RestAssured._
+import io.restassured.RestAssured.{`given`, requestSpecification}
import io.restassured.authentication.NoAuthScheme
-import io.restassured.http.{Header, Headers}
+import io.restassured.http.Header
import org.apache.http.HttpStatus.{SC_OK, SC_UNAUTHORIZED}
import org.apache.james.GuiceJamesServer
-import org.apache.james.jmap.rfc8621.contract.AuthenticationContract._
+import org.apache.james.jmap.rfc8621.contract.BasicAuthenticationContract._
import org.apache.james.jmap.rfc8621.contract.Fixture._
import org.apache.james.jmap.rfc8621.contract.tags.CategoryTags
import org.apache.james.utils.DataProbeImpl
import org.junit.jupiter.api.{BeforeEach, Tag, Test}
-object AuthenticationContract {
- private val AUTHORIZATION_HEADER: String = "Authorization"
+object BasicAuthenticationContract {
+ private def toBase64(stringValue: String): String = {
+ Base64.getEncoder.encodeToString(stringValue.getBytes(UTF_8))
+ }
}
-trait AuthenticationContract {
+trait BasicAuthenticationContract {
@BeforeEach
def setUp(server: GuiceJamesServer): Unit = {
server.getProbe(classOf[DataProbeImpl])
@@ -55,7 +38,7 @@ trait AuthenticationContract {
@Test
def postShouldRespondUnauthorizedWhenNoAuthorizationHeader(): Unit = {
- `given`()
+ given()
.header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
.body(ECHO_REQUEST_OBJECT)
.when()
@@ -137,15 +120,4 @@ trait AuthenticationContract {
.then
.statusCode(SC_UNAUTHORIZED)
}
-
- private def getHeadersWith(authHeader: Header): Headers = {
- new Headers(
- new Header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER),
- authHeader
- )
- }
-
- private def toBase64(stringValue: String): String = {
- Base64.getEncoder.encodeToString(stringValue.getBytes(UTF_8))
- }
}
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/Fixture.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/Fixture.scala
index 56be582..be44b77 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/Fixture.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/Fixture.scala
@@ -21,11 +21,12 @@ package org.apache.james.jmap.rfc8621.contract
import java.nio.charset.StandardCharsets
+import io.netty.handler.codec.http.HttpHeaderNames.ACCEPT
import io.restassured.authentication.PreemptiveBasicAuthScheme
import io.restassured.builder.RequestSpecBuilder
import io.restassured.config.EncoderConfig.encoderConfig
import io.restassured.config.RestAssuredConfig.newConfig
-import io.restassured.http.ContentType
+import io.restassured.http.{ContentType, Header, Headers}
import org.apache.james.GuiceJamesServer
import org.apache.james.core.{Domain, Username}
import org.apache.james.jmap.JMAPUrls.JMAP
@@ -50,6 +51,14 @@ object Fixture {
authScheme
}
+ def getHeadersWith(authHeader: Header): Headers = {
+ new Headers(
+ new Header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER),
+ authHeader
+ )
+ }
+
+ val AUTHORIZATION_HEADER: String = "Authorization"
val DOMAIN: Domain = Domain.of("domain.tld")
val DOMAIN_WITH_SPACE: Domain = Domain.of("dom ain.tld")
val _2_DOT_DOMAIN: Domain = Domain.of("do.main.tld")
@@ -91,4 +100,28 @@ object Fixture {
|}""".stripMargin
val ACCEPT_RFC8621_VERSION_HEADER: String = "application/json; jmapVersion=rfc-8621"
+
+ val USER: Username = Username.fromLocalPartWithDomain("user", DOMAIN)
+ val USER_PASSWORD: String = "user"
+
+ // These tokens copied from class JwtTokenVerifierTest
+ val USER_TOKEN: String =
+ "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyQGRvbWFpbi50bGQifQ.U-dUPv6OU6KO5N7CooHUfMkCd" +
+ "FJHx2F3H4fm7Q79g1BPfBSkifPj5xyVlZ0JwEGXypC4zBw9ay3l4DxzX7D_6p1Hx_ihXsoLx1Ca-WUo44x-XRSpPfgxiZjHCJkGBLMV3RZlA" +
+ "jip-d18mxkcX3JGplX_sCQkFisduAOAHuKSUg9wI6VBgUQi_0B35FYv6tP_bD6eFtvaAUN9QyXXh8UQjEp8CO12lRz6enfLx_V6BG_fEMkee" +
+ "6vRqdEqx_F9OF3eWTe1giMp_JhQ7_l1OXXtbd4TndVvTeuVy4irPbsRc-M8x_-qTDpFp6saRRsyOcFspxPp5n3yIhEK7B3UZiseXw"
+
+ val UNKNOWN_USER_TOKEN: String =
+ "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.T04BTk" +
+ "LXkJj24coSZkK13RfG25lpvmSl2MJ7N10KpBk9_-95EGYZdog-BDAn3PJzqVw52z-Bwjh4VOj1-j7cURu0cT4jXehhUrlCxS4n7QHZD" +
+ "N_bsEYGu7KzjWTpTsUiHe-rN7izXVFxDGG1TGwlmBCBnPW-EFCf9ylUsJi0r2BKNdaaPRfMIrHptH1zJBkkUziWpBN1RNLjmvlAUf49" +
+ "t1Tbv21ZqYM5Ht2vrhJWczFbuC-TD-8zJkXhjTmA1GVgomIX5dx1cH-dZX1wANNmshUJGHgepWlPU-5VIYxPEhb219RMLJIELMY2qN" +
+ "OR8Q31ydinyqzXvCSzVJOf6T60-w"
+
+ val INVALID_JWT_TOKEN: String =
+ "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbkBvcGVu" +
+ "thispartiscompletelywrong.reQc3DiVvbQHF08oW1qOUyDJyv3tfzDNk8jhVZequiCdOI9vXnRlOe" +
+ "-yDYktd4WT8MYhqY7MgS-wR0vO9jZFv8ZCgd_MkKCvCO0HmMjP5iQPZ0kqGkgWUH7X123tfR38MfbCVAdPDba-K3MfkogV1xvDhlkPScFr_6MxE" +
+ "xtedOK2JnQZn7t9sUzSrcyjWverm7gZkPptkIVoS8TsEeMMME5vFXe_nqkEG69q3kuBUm_33tbR5oNS0ZGZKlG9r41lHBjyf9J1xN4UYV8n866d" +
+ "a7RPPCzshIWUtO0q9T2umWTnp-6OnOdBCkndrZmRR6pPxsD5YL0_77Wq8KT_5__fGA"
}
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/JWTAuthenticationContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/JWTAuthenticationContract.scala
new file mode 100644
index 0000000..5fbad90
--- /dev/null
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/JWTAuthenticationContract.scala
@@ -0,0 +1,107 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+package org.apache.james.jmap.rfc8621.contract
+
+import io.restassured.RestAssured.{`given`, requestSpecification}
+import io.restassured.authentication.NoAuthScheme
+import io.restassured.http.Header
+import org.apache.http.HttpStatus._
+import org.apache.james.GuiceJamesServer
+import org.apache.james.core.Username
+import org.apache.james.jmap.rfc8621.contract.Fixture._
+import org.apache.james.jmap.rfc8621.contract.JWTAuthenticationContract._
+import org.apache.james.jmap.rfc8621.contract.tags.CategoryTags
+import org.apache.james.utils.DataProbeImpl
+import org.junit.jupiter.api.{BeforeEach, Tag, Test}
+
+object JWTAuthenticationContract {
+ private val USER_TOKEN: String =
+ "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyQGRvbWFpbi50bGQifQ.U-dUPv6OU6KO5N7CooHUfMkCd" +
+ "FJHx2F3H4fm7Q79g1BPfBSkifPj5xyVlZ0JwEGXypC4zBw9ay3l4DxzX7D_6p1Hx_ihXsoLx1Ca-WUo44x-XRSpPfgxiZjHCJkGBLMV3RZlA" +
+ "jip-d18mxkcX3JGplX_sCQkFisduAOAHuKSUg9wI6VBgUQi_0B35FYv6tP_bD6eFtvaAUN9QyXXh8UQjEp8CO12lRz6enfLx_V6BG_fEMkee" +
+ "6vRqdEqx_F9OF3eWTe1giMp_JhQ7_l1OXXtbd4TndVvTeuVy4irPbsRc-M8x_-qTDpFp6saRRsyOcFspxPp5n3yIhEK7B3UZiseXw"
+
+ private val UNKNOWN_USER_TOKEN: String =
+ "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.T04BTk" +
+ "LXkJj24coSZkK13RfG25lpvmSl2MJ7N10KpBk9_-95EGYZdog-BDAn3PJzqVw52z-Bwjh4VOj1-j7cURu0cT4jXehhUrlCxS4n7QHZD" +
+ "N_bsEYGu7KzjWTpTsUiHe-rN7izXVFxDGG1TGwlmBCBnPW-EFCf9ylUsJi0r2BKNdaaPRfMIrHptH1zJBkkUziWpBN1RNLjmvlAUf49" +
+ "t1Tbv21ZqYM5Ht2vrhJWczFbuC-TD-8zJkXhjTmA1GVgomIX5dx1cH-dZX1wANNmshUJGHgepWlPU-5VIYxPEhb219RMLJIELMY2qN" +
+ "OR8Q31ydinyqzXvCSzVJOf6T60-w"
+
+ private val INVALID_JWT_TOKEN: String =
+ "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbkBvcGVu" +
+ "thispartiscompletelywrong.reQc3DiVvbQHF08oW1qOUyDJyv3tfzDNk8jhVZequiCdOI9vXnRlOe" +
+ "-yDYktd4WT8MYhqY7MgS-wR0vO9jZFv8ZCgd_MkKCvCO0HmMjP5iQPZ0kqGkgWUH7X123tfR38MfbCVAdPDba-K3MfkogV1xvDhlkPScFr_6MxE" +
+ "xtedOK2JnQZn7t9sUzSrcyjWverm7gZkPptkIVoS8TsEeMMME5vFXe_nqkEG69q3kuBUm_33tbR5oNS0ZGZKlG9r41lHBjyf9J1xN4UYV8n866d" +
+ "a7RPPCzshIWUtO0q9T2umWTnp-6OnOdBCkndrZmRR6pPxsD5YL0_77Wq8KT_5__fGA"
+
+ private val USER: Username = Username.fromLocalPartWithDomain("user", DOMAIN)
+ private val USER_PASSWORD: String = "user"
+}
+
+trait JWTAuthenticationContract {
+ @BeforeEach
+ def setUp(server: GuiceJamesServer): Unit = {
+ server.getProbe(classOf[DataProbeImpl])
+ .fluent()
+ .addDomain(DOMAIN.asString())
+ .addUser(USER.asString(), USER_PASSWORD)
+
+ requestSpecification = baseRequestSpecBuilder(server)
+ .setAuth(new NoAuthScheme)
+ .build
+ }
+
+ @Tag(CategoryTags.BASIC_FEATURE)
+ @Test
+ def getMustReturnEndpointsWhenValidJwtAuthorizationHeader(): Unit = {
+ `given`
+ .headers(getHeadersWith(new Header(AUTHORIZATION_HEADER, s"Bearer $USER_TOKEN")))
+ .body(ECHO_REQUEST_OBJECT)
+ .when
+ .post()
+ .`then`
+ .statusCode(SC_OK)
+ }
+
+ @Test
+ @Tag(CategoryTags.BASIC_FEATURE)
+ def getMustReturnOKWhenValidUnknownUserJwtAuthorizationHeader(): Unit = {
+ val authHeader: Header = new Header(AUTHORIZATION_HEADER, s"Bearer $UNKNOWN_USER_TOKEN")
+ `given`()
+ .headers(getHeadersWith(authHeader))
+ .body(ECHO_REQUEST_OBJECT)
+ .when()
+ .post()
+ .then
+ .statusCode(SC_UNAUTHORIZED)
+ }
+
+ @Test
+ @Tag(CategoryTags.BASIC_FEATURE)
+ def getMustReturnBadCredentialsWhenInvalidJwtAuthorizationHeader(): Unit = {
+ `given`
+ .headers(getHeadersWith(new Header(AUTHORIZATION_HEADER, s"Bearer $INVALID_JWT_TOKEN")))
+ .body(ECHO_REQUEST_OBJECT)
+ .when
+ .post()
+ .`then`
+ .statusCode(SC_UNAUTHORIZED)
+ }
+}
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryAuthenticationTest.java b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryAuthenticationTest.java
index c99bf0f..5fd5b42 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryAuthenticationTest.java
+++ b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryAuthenticationTest.java
@@ -24,11 +24,11 @@ import static org.apache.james.MemoryJamesServerMain.IN_MEMORY_SERVER_AGGREGATE_
import org.apache.james.GuiceJamesServer;
import org.apache.james.JamesServerBuilder;
import org.apache.james.JamesServerExtension;
-import org.apache.james.jmap.rfc8621.contract.AuthenticationContract;
+import org.apache.james.jmap.rfc8621.contract.BasicAuthenticationContract;
import org.apache.james.modules.TestJMAPServerModule;
import org.junit.jupiter.api.extension.RegisterExtension;
-public class MemoryAuthenticationTest implements AuthenticationContract {
+public class MemoryAuthenticationTest implements BasicAuthenticationContract {
@RegisterExtension
static JamesServerExtension testExtension = new JamesServerBuilder<>(JamesServerBuilder.defaultConfigurationProvider())
.server(configuration -> GuiceJamesServer.forConfiguration(configuration)
diff --git a/server/protocols/jmap-rfc-8621/pom.xml b/server/protocols/jmap-rfc-8621/pom.xml
index feccb0c..0cf4eae 100644
--- a/server/protocols/jmap-rfc-8621/pom.xml
+++ b/server/protocols/jmap-rfc-8621/pom.xml
@@ -73,6 +73,10 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
+ <artifactId>james-server-jwt</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
<artifactId>metrics-tests</artifactId>
<scope>test</scope>
</dependency>
diff --git a/server/protocols/jmap/pom.xml b/server/protocols/jmap/pom.xml
index a052b80..37cc3db 100644
--- a/server/protocols/jmap/pom.xml
+++ b/server/protocols/jmap/pom.xml
@@ -32,11 +32,19 @@
<dependencies>
<dependency>
<groupId>${james.groupId}</groupId>
+ <artifactId>james-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
<artifactId>apache-james-mailbox-api</artifactId>
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
- <artifactId>james-core</artifactId>
+ <artifactId>james-server-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>james-server-jwt</artifactId>
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
@@ -73,15 +81,15 @@
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>javax.annotation-api</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.13</version>
</dependency>
<dependency>
- <groupId>javax.annotation</groupId>
- <artifactId>javax.annotation-api</artifactId>
- </dependency>
- <dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>test</scope>
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/exceptions/MailboxSessionCreationException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxSessionCreationException.java
similarity index 96%
rename from server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/exceptions/MailboxSessionCreationException.java
rename to server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxSessionCreationException.java
index 8865c15..a1971c2 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/exceptions/MailboxSessionCreationException.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MailboxSessionCreationException.java
@@ -17,7 +17,7 @@
* under the License. *
****************************************************************/
-package org.apache.james.jmap.draft.exceptions;
+package org.apache.james.jmap.exceptions;
public class MailboxSessionCreationException extends RuntimeException {
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/JWTAuthenticationStrategy.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/jwt/JWTAuthenticationStrategy.java
similarity index 88%
rename from server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/JWTAuthenticationStrategy.java
rename to server/protocols/jmap/src/main/java/org/apache/james/jmap/jwt/JWTAuthenticationStrategy.java
index 6f4a275..41566a7 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/JWTAuthenticationStrategy.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/jwt/JWTAuthenticationStrategy.java
@@ -16,14 +16,15 @@
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
-package org.apache.james.jmap.http;
+package org.apache.james.jmap.jwt;
import java.util.stream.Stream;
import javax.inject.Inject;
import org.apache.james.core.Username;
-import org.apache.james.jmap.draft.exceptions.MailboxSessionCreationException;
+import org.apache.james.jmap.exceptions.MailboxSessionCreationException;
+import org.apache.james.jmap.http.AuthenticationStrategy;
import org.apache.james.jwt.JwtTokenVerifier;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
@@ -37,14 +38,15 @@ import reactor.netty.http.server.HttpServerRequest;
public class JWTAuthenticationStrategy implements AuthenticationStrategy {
- @VisibleForTesting static final String AUTHORIZATION_HEADER_PREFIX = "Bearer ";
+ @VisibleForTesting
+ public static final String AUTHORIZATION_HEADER_PREFIX = "Bearer ";
private final JwtTokenVerifier tokenManager;
private final MailboxManager mailboxManager;
private final UsersRepository usersRepository;
@Inject
@VisibleForTesting
- JWTAuthenticationStrategy(JwtTokenVerifier tokenManager, MailboxManager mailboxManager, UsersRepository usersRepository) {
+ public JWTAuthenticationStrategy(JwtTokenVerifier tokenManager, MailboxManager mailboxManager, UsersRepository usersRepository) {
this.tokenManager = tokenManager;
this.mailboxManager = mailboxManager;
this.usersRepository = usersRepository;
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org