diff --git a/test-framework/security-jwt/pom.xml b/test-framework/security-jwt/pom.xml
index 0aa072bb0146d..ee3df7bf14cd9 100644
--- a/test-framework/security-jwt/pom.xml
+++ b/test-framework/security-jwt/pom.xml
@@ -28,6 +28,12 @@
junit-jupiter
compile
+
+ io.quarkus
+ quarkus-jsonp
+ compile
+ true
+
org.eclipse.microprofile.jwt
microprofile-jwt-auth-api
diff --git a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/Claim.java b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/Claim.java
index 22c2c4c3ea32b..4cbd4e90a0721 100644
--- a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/Claim.java
+++ b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/Claim.java
@@ -7,7 +7,21 @@
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Claim {
+ /**
+ * Claim name
+ */
String key();
+ /**
+ * Claim value
+ */
String value();
+
+ /**
+ * Claim value type.
+ * If this type is set to {@link ClaimType#DEFAULT} then the value will be converted to String unless the claim
+ * is a standard claim such as `exp` (expiry), `iat` (issued at), `nbf` (not before), `auth_time` (authentication time)
+ * whose value will be converted to Long or `email_verified` whose value will be converted to Boolean.
+ */
+ ClaimType type() default ClaimType.DEFAULT;
}
diff --git a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/ClaimType.java b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/ClaimType.java
new file mode 100644
index 0000000000000..7f87ce0a26c08
--- /dev/null
+++ b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/ClaimType.java
@@ -0,0 +1,59 @@
+package io.quarkus.test.security.jwt;
+
+import java.io.StringReader;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonReader;
+
+public enum ClaimType {
+ LONG {
+ @Override
+ public Long convert(String value) {
+ return Long.parseLong(value);
+ }
+ },
+ INTEGER {
+ @Override
+ public Integer convert(String value) {
+ return Integer.parseInt(value);
+ }
+ },
+ BOOLEAN {
+ @Override
+ public Boolean convert(String value) {
+ return Boolean.parseBoolean(value);
+ }
+ },
+ STRING {
+ @Override
+ public String convert(String value) {
+ return value;
+ }
+ },
+ JSON_ARRAY {
+ @Override
+ public JsonArray convert(String value) {
+ try (JsonReader jsonReader = Json.createReader(new StringReader(value))) {
+ return jsonReader.readArray();
+ }
+ }
+ },
+ JSON_OBJECT {
+ @Override
+ public JsonObject convert(String value) {
+ try (JsonReader jsonReader = Json.createReader(new StringReader(value))) {
+ return jsonReader.readObject();
+ }
+ }
+ },
+ DEFAULT {
+ @Override
+ public String convert(String value) {
+ return value;
+ }
+ };
+
+ abstract Object convert(String value);
+}
\ No newline at end of file
diff --git a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentor.java b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentor.java
new file mode 100644
index 0000000000000..76ffc96107f76
--- /dev/null
+++ b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentor.java
@@ -0,0 +1,110 @@
+package io.quarkus.test.security.jwt;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import jakarta.json.Json;
+import jakarta.json.JsonValue;
+
+import org.eclipse.microprofile.jwt.Claims;
+import org.eclipse.microprofile.jwt.JsonWebToken;
+
+import io.quarkus.security.identity.SecurityIdentity;
+import io.quarkus.security.runtime.QuarkusSecurityIdentity;
+import io.quarkus.test.security.TestSecurityIdentityAugmentor;
+
+public class JwtTestSecurityIdentityAugmentor implements TestSecurityIdentityAugmentor {
+ private static Map standardClaimTypes = Map.of(
+ Claims.exp.name(), ClaimType.LONG,
+ Claims.iat.name(), ClaimType.LONG,
+ Claims.nbf.name(), ClaimType.LONG,
+ Claims.auth_time.name(), ClaimType.LONG,
+ Claims.email_verified.name(), ClaimType.BOOLEAN);
+
+ @Override
+ public SecurityIdentity augment(final SecurityIdentity identity, final Annotation[] annotations) {
+ QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(identity);
+
+ final JwtSecurity jwtSecurity = findJwtSecurity(annotations);
+ builder.setPrincipal(new JsonWebToken() {
+
+ @Override
+ public String getName() {
+ return identity.getPrincipal().getName();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public T getClaim(String claimName) {
+ if (Claims.groups.name().equals(claimName)) {
+ return (T) identity.getRoles();
+ }
+ if (jwtSecurity != null && jwtSecurity.claims() != null) {
+ for (Claim claim : jwtSecurity.claims()) {
+ if (claim.key().equals(claimName)) {
+ return (T) wrapValue(claim, convertClaimValue(claim));
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Set getClaimNames() {
+ if (jwtSecurity != null && jwtSecurity.claims() != null) {
+ return Arrays.stream(jwtSecurity.claims()).map(Claim::key).collect(Collectors.toSet());
+ }
+ return Collections.emptySet();
+ }
+
+ });
+
+ return builder.build();
+ }
+
+ private static JwtSecurity findJwtSecurity(Annotation[] annotations) {
+ for (Annotation ann : annotations) {
+ if (ann instanceof JwtSecurity) {
+ return (JwtSecurity) ann;
+ }
+ }
+ return null;
+ }
+
+ private Object wrapValue(Claim claim, Object convertedClaimValue) {
+ Claims claimType = getClaimType(claim.key());
+ if (Claims.UNKNOWN == claimType) {
+ if (convertedClaimValue instanceof Long) {
+ return Json.createValue((Long) convertedClaimValue);
+ } else if (convertedClaimValue instanceof Integer) {
+ return Json.createValue((Integer) convertedClaimValue);
+ } else if (convertedClaimValue instanceof Boolean) {
+ return (Boolean) convertedClaimValue ? JsonValue.TRUE : JsonValue.FALSE;
+ }
+ }
+ return convertedClaimValue;
+ }
+
+ protected Claims getClaimType(String claimName) {
+ Claims claimType;
+ try {
+ claimType = Claims.valueOf(claimName);
+ } catch (IllegalArgumentException e) {
+ claimType = Claims.UNKNOWN;
+ }
+ return claimType;
+ }
+
+ private Object convertClaimValue(Claim claim) {
+ ClaimType type = claim.type();
+ if (type == ClaimType.DEFAULT && standardClaimTypes.containsKey(claim.key())) {
+ type = standardClaimTypes.get(claim.key());
+ }
+ return type.convert(claim.value());
+ }
+
+}
diff --git a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorProducer.java b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorProducer.java
index 8b4c84f120304..8e894b814459a 100644
--- a/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorProducer.java
+++ b/test-framework/security-jwt/src/main/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorProducer.java
@@ -1,20 +1,9 @@
package io.quarkus.test.security.jwt;
-import java.lang.annotation.Annotation;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Set;
-import java.util.stream.Collectors;
-
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
-import org.eclipse.microprofile.jwt.Claims;
-import org.eclipse.microprofile.jwt.JsonWebToken;
-
import io.quarkus.arc.Unremovable;
-import io.quarkus.security.identity.SecurityIdentity;
-import io.quarkus.security.runtime.QuarkusSecurityIdentity;
import io.quarkus.test.security.TestSecurityIdentityAugmentor;
@ApplicationScoped
@@ -25,57 +14,4 @@ public class JwtTestSecurityIdentityAugmentorProducer {
public TestSecurityIdentityAugmentor produce() {
return new JwtTestSecurityIdentityAugmentor();
}
-
- private static class JwtTestSecurityIdentityAugmentor implements TestSecurityIdentityAugmentor {
-
- @Override
- public SecurityIdentity augment(final SecurityIdentity identity, final Annotation[] annotations) {
- QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(identity);
-
- final JwtSecurity jwtSecurity = findJwtSecurity(annotations);
- builder.setPrincipal(new JsonWebToken() {
-
- @Override
- public String getName() {
- return identity.getPrincipal().getName();
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public T getClaim(String claimName) {
- if (Claims.groups.name().equals(claimName)) {
- return (T) identity.getRoles();
- }
- if (jwtSecurity != null && jwtSecurity.claims() != null) {
- for (Claim claim : jwtSecurity.claims()) {
- if (claim.key().equals(claimName)) {
- return (T) claim.value();
- }
- }
- }
- return null;
- }
-
- @Override
- public Set getClaimNames() {
- if (jwtSecurity != null && jwtSecurity.claims() != null) {
- return Arrays.stream(jwtSecurity.claims()).map(Claim::key).collect(Collectors.toSet());
- }
- return Collections.emptySet();
- }
-
- });
-
- return builder.build();
- }
-
- private JwtSecurity findJwtSecurity(Annotation[] annotations) {
- for (Annotation ann : annotations) {
- if (ann instanceof JwtSecurity) {
- return (JwtSecurity) ann;
- }
- }
- return null;
- }
- }
}
diff --git a/test-framework/security-jwt/src/test/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorTest.java b/test-framework/security-jwt/src/test/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorTest.java
new file mode 100644
index 0000000000000..17f0787939be7
--- /dev/null
+++ b/test-framework/security-jwt/src/test/java/io/quarkus/test/security/jwt/JwtTestSecurityIdentityAugmentorTest.java
@@ -0,0 +1,75 @@
+package io.quarkus.test.security.jwt;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.lang.annotation.Annotation;
+import java.security.Principal;
+import java.util.Set;
+
+import jakarta.json.JsonArray;
+import jakarta.json.JsonNumber;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonValue;
+
+import org.eclipse.microprofile.jwt.Claims;
+import org.eclipse.microprofile.jwt.JsonWebToken;
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.security.identity.SecurityIdentity;
+import io.quarkus.security.runtime.QuarkusSecurityIdentity;
+
+public class JwtTestSecurityIdentityAugmentorTest {
+
+ @Test
+ @JwtSecurity(claims = {
+ @Claim(key = "exp", value = "123456789"),
+ @Claim(key = "iat", value = "123456788"),
+ @Claim(key = "nbf", value = "123456787"),
+ @Claim(key = "auth_time", value = "123456786"),
+ @Claim(key = "customlong", value = "123456785", type = ClaimType.LONG),
+ @Claim(key = "email", value = "user@gmail.com"),
+ @Claim(key = "email_verified", value = "true"),
+ @Claim(key = "email_checked", value = "false", type = ClaimType.BOOLEAN),
+ @Claim(key = "jsonarray_claim", value = "[\"1\", \"2\"]", type = ClaimType.JSON_ARRAY),
+ @Claim(key = "jsonobject_claim", value = "{\"a\":\"1\", \"b\":\"2\"}", type = ClaimType.JSON_OBJECT)
+ })
+ public void testClaimValues() throws Exception {
+ SecurityIdentity identity = QuarkusSecurityIdentity.builder()
+ .setPrincipal(new Principal() {
+ @Override
+ public String getName() {
+ return "alice";
+ }
+
+ })
+ .addRole("user")
+ .build();
+
+ JwtTestSecurityIdentityAugmentor augmentor = new JwtTestSecurityIdentityAugmentor();
+
+ Annotation[] annotations = JwtTestSecurityIdentityAugmentorTest.class.getMethod("testClaimValues").getAnnotations();
+ JsonWebToken jwt = (JsonWebToken) augmentor.augment(identity, annotations).getPrincipal();
+
+ assertEquals("alice", jwt.getName());
+ assertEquals(Set.of("user"), jwt.getGroups());
+
+ assertEquals(123456789, jwt.getExpirationTime());
+ assertEquals(123456788, jwt.getIssuedAtTime());
+ assertEquals(123456787, (Long) jwt.getClaim(Claims.nbf.name()));
+ assertEquals(123456786, (Long) jwt.getClaim(Claims.auth_time.name()));
+ assertEquals(123456785, ((JsonNumber) jwt.getClaim("customlong")).longValue());
+ assertEquals("user@gmail.com", jwt.getClaim(Claims.email));
+ assertTrue((Boolean) jwt.getClaim(Claims.email_verified.name()));
+ assertEquals(JsonValue.FALSE, jwt.getClaim("email_checked"));
+
+ JsonArray array = jwt.getClaim("jsonarray_claim");
+ assertEquals("1", array.getString(0));
+ assertEquals("2", array.getString(1));
+
+ JsonObject map = jwt.getClaim("jsonobject_claim");
+ assertEquals("1", map.getString("a"));
+ assertEquals("2", map.getString("b"));
+ }
+
+}
diff --git a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/Claim.java b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/Claim.java
index a0a326a72e525..578a26b36278c 100644
--- a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/Claim.java
+++ b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/Claim.java
@@ -7,7 +7,21 @@
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Claim {
+ /**
+ * Claim name
+ */
String key();
+ /**
+ * Claim value
+ */
String value();
+
+ /**
+ * Claim value type.
+ * If this type is set to {@link ClaimType#DEFAULT} then the value will be converted to String unless the claim
+ * is a standard claim such as `exp` (expiry), `iat` (issued at), `nbf` (not before), `auth_time` (authentication time)
+ * whose value will be converted to Long or `email_verified` whose value will be converted to Boolean.
+ */
+ ClaimType type() default ClaimType.DEFAULT;
}
diff --git a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/ClaimType.java b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/ClaimType.java
new file mode 100644
index 0000000000000..f5c7722a2ff9d
--- /dev/null
+++ b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/ClaimType.java
@@ -0,0 +1,59 @@
+package io.quarkus.test.security.oidc;
+
+import java.io.StringReader;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonReader;
+
+public enum ClaimType {
+ LONG {
+ @Override
+ public Long convert(String value) {
+ return Long.parseLong(value);
+ }
+ },
+ INTEGER {
+ @Override
+ public Integer convert(String value) {
+ return Integer.parseInt(value);
+ }
+ },
+ BOOLEAN {
+ @Override
+ public Boolean convert(String value) {
+ return Boolean.parseBoolean(value);
+ }
+ },
+ STRING {
+ @Override
+ public String convert(String value) {
+ return value;
+ }
+ },
+ JSON_ARRAY {
+ @Override
+ public JsonArray convert(String value) {
+ try (JsonReader jsonReader = Json.createReader(new StringReader(value))) {
+ return jsonReader.readArray();
+ }
+ }
+ },
+ JSON_OBJECT {
+ @Override
+ public JsonObject convert(String value) {
+ try (JsonReader jsonReader = Json.createReader(new StringReader(value))) {
+ return jsonReader.readObject();
+ }
+ }
+ },
+ DEFAULT {
+ @Override
+ public String convert(String value) {
+ return value;
+ }
+ };
+
+ abstract Object convert(String value);
+}
\ No newline at end of file
diff --git a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentor.java b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentor.java
new file mode 100644
index 0000000000000..ad3d6e6aaf2eb
--- /dev/null
+++ b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentor.java
@@ -0,0 +1,164 @@
+package io.quarkus.test.security.oidc;
+
+import java.lang.annotation.Annotation;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObjectBuilder;
+
+import org.eclipse.microprofile.jwt.Claims;
+import org.eclipse.microprofile.jwt.JsonWebToken;
+import org.jose4j.jwt.JwtClaims;
+
+import io.quarkus.oidc.AccessTokenCredential;
+import io.quarkus.oidc.IdTokenCredential;
+import io.quarkus.oidc.OidcConfigurationMetadata;
+import io.quarkus.oidc.common.runtime.OidcConstants;
+import io.quarkus.oidc.runtime.OidcJwtCallerPrincipal;
+import io.quarkus.oidc.runtime.OidcUtils;
+import io.quarkus.security.identity.SecurityIdentity;
+import io.quarkus.security.runtime.QuarkusSecurityIdentity;
+import io.quarkus.test.security.TestSecurityIdentityAugmentor;
+import io.smallrye.jwt.build.Jwt;
+import io.smallrye.jwt.util.KeyUtils;
+import io.vertx.core.json.JsonObject;
+
+public class OidcTestSecurityIdentityAugmentor implements TestSecurityIdentityAugmentor {
+
+ private static Map standardClaimTypes = Map.of(
+ Claims.exp.name(), ClaimType.LONG,
+ Claims.iat.name(), ClaimType.LONG,
+ Claims.nbf.name(), ClaimType.LONG,
+ Claims.auth_time.name(), ClaimType.LONG,
+ Claims.email_verified.name(), ClaimType.BOOLEAN);
+
+ private Optional issuer;
+ private PrivateKey privateKey;
+
+ public OidcTestSecurityIdentityAugmentor(Optional issuer) {
+ this.issuer = issuer;
+ try {
+ privateKey = KeyUtils.generateKeyPair(2048).getPrivate();
+ } catch (NoSuchAlgorithmException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ public SecurityIdentity augment(final SecurityIdentity identity, final Annotation[] annotations) {
+ QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(identity);
+
+ final OidcSecurity oidcSecurity = findOidcSecurity(annotations);
+
+ final boolean introspectionRequired = oidcSecurity != null && oidcSecurity.introspectionRequired();
+
+ if (!introspectionRequired) {
+ // JsonWebToken
+ JsonObjectBuilder claims = Json.createObjectBuilder();
+ claims.add(Claims.preferred_username.name(), identity.getPrincipal().getName());
+ claims.add(Claims.groups.name(),
+ Json.createArrayBuilder(identity.getRoles().stream().collect(Collectors.toList())).build());
+ if (oidcSecurity != null && oidcSecurity.claims() != null) {
+ for (Claim claim : oidcSecurity.claims()) {
+ Object claimValue = convertClaimValue(claim);
+ if (claimValue instanceof String) {
+ claims.add(claim.key(), (String) claimValue);
+ } else if (claimValue instanceof Long) {
+ claims.add(claim.key(), (Long) claimValue);
+ } else if (claimValue instanceof Integer) {
+ claims.add(claim.key(), (Integer) claimValue);
+ } else if (claimValue instanceof Boolean) {
+ claims.add(claim.key(), (Boolean) claimValue);
+ } else if (claimValue instanceof JsonArray) {
+ claims.add(claim.key(), (JsonArray) claimValue);
+ } else if (claimValue instanceof jakarta.json.JsonObject) {
+ claims.add(claim.key(), (jakarta.json.JsonObject) claimValue);
+ }
+ }
+ }
+ jakarta.json.JsonObject claimsJson = claims.build();
+ String jwt = generateToken(claimsJson);
+ IdTokenCredential idToken = new IdTokenCredential(jwt);
+ AccessTokenCredential accessToken = new AccessTokenCredential(jwt);
+
+ try {
+ JsonWebToken principal = new OidcJwtCallerPrincipal(JwtClaims.parse(claimsJson.toString()), idToken);
+ builder.setPrincipal(principal);
+ } catch (Exception ex) {
+ throw new RuntimeException();
+ }
+ builder.addCredential(idToken);
+ builder.addCredential(accessToken);
+ } else {
+ JsonObjectBuilder introspectionBuilder = Json.createObjectBuilder();
+ introspectionBuilder.add(OidcConstants.INTROSPECTION_TOKEN_ACTIVE, true);
+ introspectionBuilder.add(OidcConstants.INTROSPECTION_TOKEN_USERNAME, identity.getPrincipal().getName());
+ introspectionBuilder.add(OidcConstants.TOKEN_SCOPE,
+ identity.getRoles().stream().collect(Collectors.joining(" ")));
+
+ if (oidcSecurity != null && oidcSecurity.introspection() != null) {
+ for (TokenIntrospection introspection : oidcSecurity.introspection()) {
+ introspectionBuilder.add(introspection.key(), introspection.value());
+ }
+ }
+
+ builder.addAttribute(OidcUtils.INTROSPECTION_ATTRIBUTE,
+ new io.quarkus.oidc.TokenIntrospection(introspectionBuilder.build()));
+ builder.addCredential(new AccessTokenCredential(UUID.randomUUID().toString(), null));
+ }
+
+ // UserInfo
+ if (oidcSecurity != null && oidcSecurity.userinfo() != null) {
+ JsonObjectBuilder userInfoBuilder = Json.createObjectBuilder();
+ for (UserInfo userinfo : oidcSecurity.userinfo()) {
+ userInfoBuilder.add(userinfo.key(), userinfo.value());
+ }
+ builder.addAttribute(OidcUtils.USER_INFO_ATTRIBUTE, new io.quarkus.oidc.UserInfo(userInfoBuilder.build()));
+ }
+
+ // OidcConfigurationMetadata
+ JsonObject configMetadataBuilder = new JsonObject();
+ if (issuer.isPresent()) {
+ configMetadataBuilder.put("issuer", issuer.get());
+ }
+ if (oidcSecurity != null && oidcSecurity.config() != null) {
+ for (ConfigMetadata config : oidcSecurity.config()) {
+ configMetadataBuilder.put(config.key(), config.value());
+ }
+ }
+ builder.addAttribute(OidcUtils.CONFIG_METADATA_ATTRIBUTE, new OidcConfigurationMetadata(configMetadataBuilder));
+
+ return builder.build();
+ }
+
+ private String generateToken(jakarta.json.JsonObject claims) {
+ try {
+ return Jwt.claims(claims).sign(privateKey);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static OidcSecurity findOidcSecurity(Annotation[] annotations) {
+ for (Annotation ann : annotations) {
+ if (ann instanceof OidcSecurity) {
+ return (OidcSecurity) ann;
+ }
+ }
+ return null;
+ }
+
+ private Object convertClaimValue(Claim claim) {
+ ClaimType type = claim.type();
+ if (type == ClaimType.DEFAULT && standardClaimTypes.containsKey(claim.key())) {
+ type = standardClaimTypes.get(claim.key());
+ }
+ return type.convert(claim.value());
+ }
+}
diff --git a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorProducer.java b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorProducer.java
index accf1ce2042f3..8e49aaaa0c2c6 100644
--- a/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorProducer.java
+++ b/test-framework/security-oidc/src/main/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorProducer.java
@@ -1,37 +1,15 @@
package io.quarkus.test.security.oidc;
-import java.lang.annotation.Annotation;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
import java.util.Optional;
-import java.util.UUID;
-import java.util.stream.Collectors;
-import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Inject;
-import jakarta.json.Json;
-import jakarta.json.JsonObjectBuilder;
import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.eclipse.microprofile.jwt.Claims;
-import org.eclipse.microprofile.jwt.JsonWebToken;
-import org.jose4j.jwt.JwtClaims;
import io.quarkus.arc.Unremovable;
-import io.quarkus.oidc.AccessTokenCredential;
-import io.quarkus.oidc.IdTokenCredential;
-import io.quarkus.oidc.OidcConfigurationMetadata;
-import io.quarkus.oidc.common.runtime.OidcConstants;
-import io.quarkus.oidc.runtime.OidcJwtCallerPrincipal;
-import io.quarkus.oidc.runtime.OidcUtils;
-import io.quarkus.security.identity.SecurityIdentity;
-import io.quarkus.security.runtime.QuarkusSecurityIdentity;
import io.quarkus.test.security.TestSecurityIdentityAugmentor;
-import io.smallrye.jwt.build.Jwt;
-import io.smallrye.jwt.util.KeyUtils;
-import io.vertx.core.json.JsonObject;
@ApplicationScoped
public class OidcTestSecurityIdentityAugmentorProducer {
@@ -40,109 +18,9 @@ public class OidcTestSecurityIdentityAugmentorProducer {
@ConfigProperty(name = "quarkus.oidc.token.issuer")
Optional issuer;
- PrivateKey privateKey;
-
- @PostConstruct
- public void init() {
- try {
- privateKey = KeyUtils.generateKeyPair(2048).getPrivate();
- } catch (NoSuchAlgorithmException ex) {
- throw new RuntimeException(ex);
- }
- }
-
@Produces
@Unremovable
public TestSecurityIdentityAugmentor produce() {
- return new OidcTestSecurityIdentityAugmentor();
- }
-
- private class OidcTestSecurityIdentityAugmentor implements TestSecurityIdentityAugmentor {
-
- @Override
- public SecurityIdentity augment(final SecurityIdentity identity, final Annotation[] annotations) {
- QuarkusSecurityIdentity.Builder builder = QuarkusSecurityIdentity.builder(identity);
-
- final OidcSecurity oidcSecurity = findOidcSecurity(annotations);
-
- final boolean introspectionRequired = oidcSecurity != null && oidcSecurity.introspectionRequired();
-
- if (!introspectionRequired) {
- // JsonWebToken
- JwtClaims claims = new JwtClaims();
- claims.setClaim(Claims.preferred_username.name(), identity.getPrincipal().getName());
- claims.setClaim(Claims.groups.name(), identity.getRoles().stream().collect(Collectors.toList()));
- if (oidcSecurity != null && oidcSecurity.claims() != null) {
- for (Claim claim : oidcSecurity.claims()) {
- claims.setClaim(claim.key(), claim.value());
- }
- }
- String jwt = generateToken(claims);
- IdTokenCredential idToken = new IdTokenCredential(jwt);
- AccessTokenCredential accessToken = new AccessTokenCredential(jwt);
-
- JsonWebToken principal = new OidcJwtCallerPrincipal(claims, idToken);
- builder.setPrincipal(principal);
- builder.addCredential(idToken);
- builder.addCredential(accessToken);
- } else {
- JsonObjectBuilder introspectionBuilder = Json.createObjectBuilder();
- introspectionBuilder.add(OidcConstants.INTROSPECTION_TOKEN_ACTIVE, true);
- introspectionBuilder.add(OidcConstants.INTROSPECTION_TOKEN_USERNAME, identity.getPrincipal().getName());
- introspectionBuilder.add(OidcConstants.TOKEN_SCOPE,
- identity.getRoles().stream().collect(Collectors.joining(" ")));
-
- if (oidcSecurity != null && oidcSecurity.introspection() != null) {
- for (TokenIntrospection introspection : oidcSecurity.introspection()) {
- introspectionBuilder.add(introspection.key(), introspection.value());
- }
- }
-
- builder.addAttribute(OidcUtils.INTROSPECTION_ATTRIBUTE,
- new io.quarkus.oidc.TokenIntrospection(introspectionBuilder.build()));
- builder.addCredential(new AccessTokenCredential(UUID.randomUUID().toString(), null));
- }
-
- // UserInfo
- if (oidcSecurity != null && oidcSecurity.userinfo() != null) {
- JsonObjectBuilder userInfoBuilder = Json.createObjectBuilder();
- for (UserInfo userinfo : oidcSecurity.userinfo()) {
- userInfoBuilder.add(userinfo.key(), userinfo.value());
- }
- builder.addAttribute(OidcUtils.USER_INFO_ATTRIBUTE, new io.quarkus.oidc.UserInfo(userInfoBuilder.build()));
- }
-
- // OidcConfigurationMetadata
- JsonObject configMetadataBuilder = new JsonObject();
- if (issuer.isPresent()) {
- configMetadataBuilder.put("issuer", issuer.get());
- }
- if (oidcSecurity != null && oidcSecurity.config() != null) {
- for (ConfigMetadata config : oidcSecurity.config()) {
- configMetadataBuilder.put(config.key(), config.value());
- }
- }
- builder.addAttribute(OidcUtils.CONFIG_METADATA_ATTRIBUTE, new OidcConfigurationMetadata(configMetadataBuilder));
-
- return builder.build();
- }
-
- private String generateToken(JwtClaims claims) {
- try {
- return Jwt.claims(claims.getClaimsMap()).sign(privateKey);
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private OidcSecurity findOidcSecurity(Annotation[] annotations) {
- for (Annotation ann : annotations) {
- if (ann instanceof OidcSecurity) {
- return (OidcSecurity) ann;
- }
- }
- return null;
- }
+ return new OidcTestSecurityIdentityAugmentor(issuer);
}
-
}
diff --git a/test-framework/security-oidc/src/test/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorTest.java b/test-framework/security-oidc/src/test/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorTest.java
new file mode 100644
index 0000000000000..6b7fc8cb1519d
--- /dev/null
+++ b/test-framework/security-oidc/src/test/java/io/quarkus/test/security/oidc/OidcTestSecurityIdentityAugmentorTest.java
@@ -0,0 +1,76 @@
+package io.quarkus.test.security.oidc;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.lang.annotation.Annotation;
+import java.security.Principal;
+import java.util.Optional;
+import java.util.Set;
+
+import jakarta.json.JsonArray;
+import jakarta.json.JsonNumber;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonValue;
+
+import org.eclipse.microprofile.jwt.Claims;
+import org.eclipse.microprofile.jwt.JsonWebToken;
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.security.identity.SecurityIdentity;
+import io.quarkus.security.runtime.QuarkusSecurityIdentity;
+
+public class OidcTestSecurityIdentityAugmentorTest {
+
+ @Test
+ @OidcSecurity(claims = {
+ @Claim(key = "exp", value = "123456789"),
+ @Claim(key = "iat", value = "123456788"),
+ @Claim(key = "nbf", value = "123456787"),
+ @Claim(key = "auth_time", value = "123456786"),
+ @Claim(key = "customlong", value = "123456785", type = ClaimType.LONG),
+ @Claim(key = "email", value = "user@gmail.com"),
+ @Claim(key = "email_verified", value = "true"),
+ @Claim(key = "email_checked", value = "false", type = ClaimType.BOOLEAN),
+ @Claim(key = "jsonarray_claim", value = "[\"1\", \"2\"]", type = ClaimType.JSON_ARRAY),
+ @Claim(key = "jsonobject_claim", value = "{\"a\":\"1\", \"b\":\"2\"}", type = ClaimType.JSON_OBJECT)
+ })
+ public void testClaimValues() throws Exception {
+ SecurityIdentity identity = QuarkusSecurityIdentity.builder()
+ .setPrincipal(new Principal() {
+ @Override
+ public String getName() {
+ return "alice";
+ }
+
+ })
+ .addRole("user")
+ .build();
+
+ OidcTestSecurityIdentityAugmentor augmentor = new OidcTestSecurityIdentityAugmentor(Optional.of("https://issuer.org"));
+
+ Annotation[] annotations = OidcTestSecurityIdentityAugmentorTest.class.getMethod("testClaimValues").getAnnotations();
+ JsonWebToken jwt = (JsonWebToken) augmentor.augment(identity, annotations).getPrincipal();
+
+ assertEquals("alice", jwt.getName());
+ assertEquals(Set.of("user"), jwt.getGroups());
+
+ assertEquals(123456789, jwt.getExpirationTime());
+ assertEquals(123456788, jwt.getIssuedAtTime());
+ assertEquals(123456787, (Long) jwt.getClaim(Claims.nbf.name()));
+ assertEquals(123456786, (Long) jwt.getClaim(Claims.auth_time.name()));
+ assertEquals(123456785, ((JsonNumber) jwt.getClaim("customlong")).longValue());
+ assertEquals("user@gmail.com", jwt.getClaim(Claims.email));
+ assertTrue((Boolean) jwt.getClaim(Claims.email_verified.name()));
+ assertEquals(JsonValue.FALSE, jwt.getClaim("email_checked"));
+
+ JsonArray array = jwt.getClaim("jsonarray_claim");
+ assertEquals("1", array.getString(0));
+ assertEquals("2", array.getString(1));
+
+ JsonObject map = jwt.getClaim("jsonobject_claim");
+ assertEquals("1", map.getString("a"));
+ assertEquals("2", map.getString("b"));
+ }
+
+}