diff --git a/doc/modules/ROOT/pages/configuration.adoc b/doc/modules/ROOT/pages/configuration.adoc index 9043583d..6d5a122d 100644 --- a/doc/modules/ROOT/pages/configuration.adoc +++ b/doc/modules/ROOT/pages/configuration.adoc @@ -39,6 +39,7 @@ SmallRye JWT supports many properties which can be used to customize the token p [cols=" decryptionKey) { - return create(publicKey, keyLocation, Optional.empty(), Optional.empty(), Optional.empty(), + return create(key, keyLocation, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), secretKey, verifyCertificateThumbprint, issuer, decryptionKey); } - private static JWTAuthContextInfoProvider create(String publicKey, + private static JWTAuthContextInfoProvider create(String key, String keyLocation, Optional theKeyStoreType, Optional theKeyStoreProvider, @@ -158,7 +158,8 @@ private static JWTAuthContextInfoProvider create(String publicKey, String issuer, Optional decryptionKey) { JWTAuthContextInfoProvider provider = new JWTAuthContextInfoProvider(); - provider.mpJwtPublicKey = publicKey; + provider.mpJwtPublicKey = !secretKey ? key : NONE; + provider.jwtSecretKey = secretKey ? key : NONE; provider.mpJwtPublicKeyAlgorithm = Optional.of(SignatureAlgorithm.RS256); provider.mpJwtLocation = !secretKey && !theKeyStoreDecryptKeyAlias.isPresent() ? keyLocation : NONE; provider.verifyKeyLocation = secretKey ? keyLocation : NONE; @@ -217,6 +218,13 @@ private static JWTAuthContextInfoProvider create(String publicKey, @Inject @ConfigProperty(name = "mp.jwt.verify.publickey", defaultValue = NONE) private String mpJwtPublicKey; + + /** + * @since 4.5.4 + */ + @Inject + @ConfigProperty(name = "smallrye.jwt.verify.secretkey", defaultValue = NONE) + private String jwtSecretKey; /** * @since 1.2 */ @@ -668,9 +676,20 @@ Optional getOptionalContextInfo() { contextInfo.setIssuedBy(mpJwtIssuer.trim()); } - if (!NONE.equals(mpJwtPublicKey)) { + final boolean verificationPublicKeySet = !NONE.equals(mpJwtPublicKey); + final boolean verificationSecretKeySet = !NONE.equals(jwtSecretKey); + final boolean verificationKeyLocationSet = !NONE.equals(resolvedVerifyKeyLocation); + if (verificationPublicKeySet) { contextInfo.setPublicKeyContent(mpJwtPublicKey); - } else if (!NONE.equals(resolvedVerifyKeyLocation)) { + if (verificationKeyLocationSet || verificationSecretKeySet) { + ConfigLogging.log.publicKeyConfiguredButOtherKeyPropertiesAreAlsoUsed(); + } + } else if (verificationSecretKeySet) { + contextInfo.setSecretKeyContent(jwtSecretKey); + if (verificationKeyLocationSet) { + ConfigLogging.log.secretKeyConfiguredButKeyLocationIsAlsoUsed(); + } + } else if (verificationKeyLocationSet) { String resolvedVerifyKeyLocationTrimmed = resolvedVerifyKeyLocation.trim(); if (resolvedVerifyKeyLocationTrimmed.startsWith("http")) { if (fetchRemoteKeysOnStartup) { diff --git a/testsuite/basic/src/test/java/io/smallrye/jwt/auth/principal/KeyLocationResolverTest.java b/testsuite/basic/src/test/java/io/smallrye/jwt/auth/principal/KeyLocationResolverTest.java index 4ab85065..23c5bfe5 100644 --- a/testsuite/basic/src/test/java/io/smallrye/jwt/auth/principal/KeyLocationResolverTest.java +++ b/testsuite/basic/src/test/java/io/smallrye/jwt/auth/principal/KeyLocationResolverTest.java @@ -21,8 +21,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import java.nio.charset.StandardCharsets; import java.security.PrivateKey; import java.time.Instant; +import java.util.Base64; +import java.util.Optional; import org.eclipse.microprofile.jwt.tck.util.TokenUtils; import org.jose4j.jwt.JwtClaims; @@ -190,6 +193,45 @@ void verifyTokenSignedWithSecretKey() throws Exception { assertEquals("Alice", jwt.getClaimValueAsString("upn")); } + @Test + void verifyTokenSignedWithInlinedSecretKey() throws Exception { + String jwtString = Jwt.issuer("https://server.example.com").upn("Alice").sign("secretKey.jwk"); + JWTAuthContextInfoProvider provider = JWTAuthContextInfoProvider + .create("{\n" + + " \"kty\":\"oct\",\n" + + " \"k\":\"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I\"\n" + + " }", + null, + true, + false, + "https://server.example.com", + Optional.empty()); + JWTAuthContextInfo contextInfo = provider.getContextInfo(); + contextInfo.setSignatureAlgorithm(SignatureAlgorithm.HS256); + JwtClaims jwt = new DefaultJWTTokenParser().parse(jwtString, contextInfo).getJwtClaims(); + assertEquals("Alice", jwt.getClaimValueAsString("upn")); + } + + @Test + void verifyTokenSignedWithInlinedBase64UrlEncodedSecretKey() throws Exception { + String jwtString = Jwt.issuer("https://server.example.com").upn("Alice").sign("secretKey.jwk"); + byte[] bytes = ("{\n" + + " \"kty\":\"oct\",\n" + + " \"k\":\"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I\"\n" + + " }").getBytes(StandardCharsets.UTF_8); + JWTAuthContextInfoProvider provider = JWTAuthContextInfoProvider + .create(Base64.getUrlEncoder().withoutPadding().encodeToString(bytes), + null, + true, + false, + "https://server.example.com", + Optional.empty()); + JWTAuthContextInfo contextInfo = provider.getContextInfo(); + contextInfo.setSignatureAlgorithm(SignatureAlgorithm.HS256); + JwtClaims jwt = new DefaultJWTTokenParser().parse(jwtString, contextInfo).getJwtClaims(); + assertEquals("Alice", jwt.getClaimValueAsString("upn")); + } + @Test void decryptToken() throws Exception { String jwtString = Jwt.issuer("https://server.example.com").upn("Alice").jwe().encrypt("publicKey.pem");