You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by jg...@apache.org on 2023/12/06 16:13:16 UTC
(tomee) 01/02: Implement tomee.mp.jwt.allow.no-exp property over mp.jwt.tomee.allow.no-exp
This is an automated email from the ASF dual-hosted git repository.
jgallimore pushed a commit to branch tomee-9.x
in repository https://gitbox.apache.org/repos/asf/tomee.git
commit 8414084c93193767bea7b81783de53a7be866e08
Author: Zoltán Tichov <zo...@gmail.com>
AuthorDate: Sun Dec 18 12:37:48 2022 +0100
Implement tomee.mp.jwt.allow.no-exp property over mp.jwt.tomee.allow.no-exp
---
docs/microprofile/jwt.adoc | 3 +-
.../jwt/itest/AllowNoExpPropertyTest.java | 253 +++++++++++++++++++++
.../jwt/config/JWTAuthConfigurationProperties.java | 15 +-
3 files changed, 268 insertions(+), 3 deletions(-)
diff --git a/docs/microprofile/jwt.adoc b/docs/microprofile/jwt.adoc
index 270be03e6e..d1b2e948e0 100644
--- a/docs/microprofile/jwt.adoc
+++ b/docs/microprofile/jwt.adoc
@@ -81,7 +81,8 @@ In addition to the standard MicroProfile JWT configuration properties above, the
| Property
| Type
| Description
-| `mp.jwt.tomee.allow.no-exp`
+| `mp.jwt.tomee.allow.no-exp` is deprecated please use `tomee.mp.jwt.allow.no-exp` property instead
+| `tomee.mp.jwt.allow.no-exp`
| Boolean
| Disables enforcing the `exp` time of the JWT. Useful if JWTs are also verified by an API Gateway or proxy before reaching the server. The default value is `false`
| `tomee.jwt.verify.publickey.cache`
diff --git a/itests/microprofile-jwt-itests/src/test/java/org/apache/tomee/microprofile/jwt/itest/AllowNoExpPropertyTest.java b/itests/microprofile-jwt-itests/src/test/java/org/apache/tomee/microprofile/jwt/itest/AllowNoExpPropertyTest.java
new file mode 100644
index 0000000000..467cc17a6d
--- /dev/null
+++ b/itests/microprofile-jwt-itests/src/test/java/org/apache/tomee/microprofile/jwt/itest/AllowNoExpPropertyTest.java
@@ -0,0 +1,253 @@
+/*
+ * 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.tomee.microprofile.jwt.itest;
+
+import jakarta.annotation.security.RolesAllowed;
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Base64;
+import static java.util.Collections.singletonList;
+import java.util.Optional;
+import org.apache.cxf.feature.LoggingFeature;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.johnzon.jaxrs.JohnzonProvider;
+import org.apache.tomee.server.composer.Archive;
+import org.apache.tomee.server.composer.TomEE;
+import org.eclipse.microprofile.auth.LoginConfig;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+
+public class AllowNoExpPropertyTest {
+
+ @Test
+ public void testNewPropertyOverridesOld1() throws Exception {
+ final Tokens tokens = Tokens.rsa(2048, 256);
+ final File appJar = Archive.archive()
+ .add(AllowNoExpPropertyTest.class)
+ .add(ColorService.class)
+ .add(Api.class)
+ .add("META-INF/microprofile-config.properties", "#\n" +
+ "mp.jwt.verify.publickey=" + Base64.getEncoder().encodeToString(tokens.getPublicKey().getEncoded())
+ + "\n" + "mp.jwt.tomee.allow.no-exp=false"
+ + "\n" + "tomee.mp.jwt.allow.no-exp=true")
+ .asJar();
+
+ final ArrayList<String> output = new ArrayList<>();
+ final TomEE tomee = TomEE.microprofile()
+ .add("webapps/test/WEB-INF/beans.xml", "")
+ .add("webapps/test/WEB-INF/lib/app.jar", appJar)
+ .watch("org.apache.tomee.microprofile.jwt.", "\n", output::add)
+ .build();
+
+ final WebClient webClient = createWebClient(tomee.toURI().resolve("/test").toURL());
+
+ final String claims = "{" +
+ " \"sub\":\"Jane Awesome\"" +
+ "}";
+
+ {// invalid token
+ final String token = tokens.asToken(claims);
+ final Response response = webClient.reset()
+ .path("/movies")
+ .header("Content-Type", "application/json")
+ .header("Authorization", "Bearer " + token)
+ .get();
+ assertEquals(403, response.getStatus());
+ }
+
+ assertPresent(output , "mp.jwt.tomee.allow.no-exp property is deprecated");
+ assertNotPresent(output, "rejected due to invalid claims");
+ assertNotPresent(output, "No Expiration Time (exp) claim present.");
+ assertNotPresent(output, "\tat org."); // no stack traces
+ }
+
+ @Test
+ public void testNewPropertyOverridesOld2() throws Exception {
+ final Tokens tokens = Tokens.rsa(2048, 256);
+ final File appJar = Archive.archive()
+ .add(AllowNoExpPropertyTest.class)
+ .add(ColorService.class)
+ .add(Api.class)
+ .add("META-INF/microprofile-config.properties", "#\n" +
+ "mp.jwt.verify.publickey=" + Base64.getEncoder().encodeToString(tokens.getPublicKey().getEncoded())
+ + "\n" + "mp.jwt.tomee.allow.no-exp=true"
+ + "\n" + "tomee.mp.jwt.allow.no-exp=false")
+ .asJar();
+
+ final ArrayList<String> output = new ArrayList<>();
+ final TomEE tomee = TomEE.microprofile()
+ .add("webapps/test/WEB-INF/beans.xml", "")
+ .add("webapps/test/WEB-INF/lib/app.jar", appJar)
+ .watch("org.apache.tomee.microprofile.jwt.", "\n", output::add)
+ .build();
+
+ final WebClient webClient = createWebClient(tomee.toURI().resolve("/test").toURL());
+
+ final String claims = "{" +
+ " \"sub\":\"Jane Awesome\"" +
+ "}";
+
+ {// invalid token
+ final String token = tokens.asToken(claims);
+ final Response response = webClient.reset()
+ .path("/movies")
+ .header("Content-Type", "application/json")
+ .header("Authorization", "Bearer " + token)
+ .get();
+ assertEquals(401, response.getStatus());
+ }
+
+ assertPresent(output , "mp.jwt.tomee.allow.no-exp property is deprecated");
+ assertPresent(output, "rejected due to invalid claims");
+ assertPresent(output, "No Expiration Time (exp) claim present.");
+ assertNotPresent(output, "\tat org."); // no stack traces
+ }
+
+ @Test
+ public void testNewProperty() throws Exception {
+ final Tokens tokens = Tokens.rsa(2048, 256);
+ final File appJar = Archive.archive()
+ .add(AllowNoExpPropertyTest.class)
+ .add(ColorService.class)
+ .add(Api.class)
+ .add("META-INF/microprofile-config.properties", "#\n" +
+ "mp.jwt.verify.publickey=" + Base64.getEncoder().encodeToString(tokens.getPublicKey().getEncoded())
+ + "\n" + "tomee.mp.jwt.allow.no-exp=true")
+ .asJar();
+
+ final ArrayList<String> output = new ArrayList<>();
+ final TomEE tomee = TomEE.microprofile()
+ .add("webapps/test/WEB-INF/beans.xml", "")
+ .add("webapps/test/WEB-INF/lib/app.jar", appJar)
+ .watch("org.apache.tomee.microprofile.jwt.", "\n", output::add)
+ .build();
+
+ final WebClient webClient = createWebClient(tomee.toURI().resolve("/test").toURL());
+
+ final String claims = "{" +
+ " \"sub\":\"Jane Awesome\"" +
+ "}";
+
+ {// invalid token
+ final String token = tokens.asToken(claims);
+ final Response response = webClient.reset()
+ .path("/movies")
+ .header("Content-Type", "application/json")
+ .header("Authorization", "Bearer " + token)
+ .get();
+ assertEquals(403, response.getStatus());
+ }
+
+ assertNotPresent(output , "mp.jwt.tomee.allow.no-exp property is deprecated");
+ assertNotPresent(output, "rejected due to invalid claims");
+ assertNotPresent(output, "No Expiration Time (exp) claim present.");
+ assertNotPresent(output, "\tat org."); // no stack traces
+ }
+
+ @Test
+ public void testOldProperty() throws Exception {
+ final Tokens tokens = Tokens.rsa(2048, 256);
+ final File appJar = Archive.archive()
+ .add(AllowNoExpPropertyTest.class)
+ .add(ColorService.class)
+ .add(Api.class)
+ .add("META-INF/microprofile-config.properties", "#\n" +
+ "mp.jwt.verify.publickey=" + Base64.getEncoder().encodeToString(tokens.getPublicKey().getEncoded())
+ + "\n" + "mp.jwt.tomee.allow.no-exp=true")
+ .asJar();
+
+ final ArrayList<String> output = new ArrayList<>();
+ final TomEE tomee = TomEE.microprofile()
+ .add("webapps/test/WEB-INF/beans.xml", "")
+ .add("webapps/test/WEB-INF/lib/app.jar", appJar)
+ .watch("org.apache.tomee.microprofile.jwt.", "\n", output::add)
+ .build();
+
+ final WebClient webClient = createWebClient(tomee.toURI().resolve("/test").toURL());
+
+ final String claims = "{" +
+ " \"sub\":\"Jane Awesome\"" +
+ "}";
+
+ {// invalid token
+ final String token = tokens.asToken(claims);
+ final Response response = webClient.reset()
+ .path("/movies")
+ .header("Content-Type", "application/json")
+ .header("Authorization", "Bearer " + token)
+ .get();
+ assertEquals(403, response.getStatus());
+ }
+
+ assertPresent(output , "mp.jwt.tomee.allow.no-exp property is deprecated");
+ assertNotPresent(output, "rejected due to invalid claims");
+ assertNotPresent(output, "No Expiration Time (exp) claim present.");
+ assertNotPresent(output, "\tat org."); // no stack traces
+ }
+
+ public void assertPresent(final ArrayList<String> output, final String s) {
+ final Optional<String> actual = output.stream()
+ .filter(line -> line.contains(s))
+ .findFirst();
+
+ assertTrue(actual.isPresent());
+ }
+ public void assertNotPresent(final ArrayList<String> output, final String s) {
+ final Optional<String> actual = output.stream()
+ .filter(line -> line.contains(s))
+ .findFirst();
+
+ assertTrue(!actual.isPresent());
+ }
+
+ private static WebClient createWebClient(final URL base) {
+ return WebClient.create(base.toExternalForm(), singletonList(new JohnzonProvider<>()),
+ singletonList(new LoggingFeature()), null);
+ }
+
+ @ApplicationPath("/api")
+ @LoginConfig(authMethod = "MP-JWT")
+ public class Api extends Application {
+ }
+
+ @Path("/movies")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @RequestScoped
+ public static class ColorService {
+
+ @GET
+ @RolesAllowed({"manager", "user"})
+ public String getAllMovies() {
+ return "Green";
+ }
+ }
+
+}
diff --git a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfigurationProperties.java b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfigurationProperties.java
index e2f4823eef..65fac63995 100644
--- a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfigurationProperties.java
+++ b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfigurationProperties.java
@@ -38,6 +38,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import static org.eclipse.microprofile.jwt.config.Names.AUDIENCES;
@@ -59,6 +60,7 @@ import static org.eclipse.microprofile.jwt.config.Names.VERIFIER_PUBLIC_KEY_LOCA
public class JWTAuthConfigurationProperties {
public static final String PUBLIC_KEY_ERROR = "Could not read MicroProfile Public Key";
public static final String PUBLIC_KEY_ERROR_LOCATION = PUBLIC_KEY_ERROR + " from Location: ";
+ private static final Logger CONFIGURATION = Logger.getInstance(JWTLogCategories.CONFIG, JWTAuthConfigurationProperties.class);
private Config config;
private JWTAuthConfiguration jwtAuthConfiguration;
@@ -104,8 +106,8 @@ public class JWTAuthConfigurationProperties {
final Supplier<Map<String, Key>> publicKeys = Keys.VERIFY.configure(config);
final Supplier<Map<String, Key>> decryptKeys = Keys.DECRYPT.configure(config);
- final Boolean allowNoExp = config.getOptionalValue("mp.jwt.tomee.allow.no-exp", Boolean.class).orElse(false);
-
+ final Boolean allowNoExp = queryAllowExp();
+
return new JWTAuthConfiguration(
publicKeys,
getIssuer().orElse(null),
@@ -117,6 +119,15 @@ public class JWTAuthConfigurationProperties {
config.getOptionalValue("mp.jwt.decrypt.key.algorithm", String.class).orElse(null),
config.getOptionalValue("mp.jwt.verify.publickey.algorithm", String.class).orElse(null));
}
+
+ private Boolean queryAllowExp(){
+ AtomicBoolean result = new AtomicBoolean(false);
+ config.getOptionalValue("mp.jwt.tomee.allow.no-exp", Boolean.class).ifPresent(value -> {
+ result.set(value);
+ CONFIGURATION.warning("mp.jwt.tomee.allow.no-exp property is deprecated, use tomee.mp.jwt.allow.no-exp propert instead.");
+ });
+ return config.getOptionalValue("tomee.mp.jwt.allow.no-exp", Boolean.class).orElse(result.get());
+ }
enum Keys {
VERIFY("mp.jwt.verify.publickey", "tomee.jwt.verify.publickey"),