Skip to content

Commit c0bfa66

Browse files
authored
SignedJwt's parseToken() expects characters from base64 instead of ba… (helidon-io#3722)
* SignedJwt's parseToken() expects characters from base64 instead of base64URL encoding * Additional Unit tests to verify SignedJwt's parseToken()
1 parent 0037c41 commit c0bfa66

2 files changed

Lines changed: 50 additions & 1 deletion

File tree

security/jwt/src/main/java/io/helidon/security/jwt/SignedJwt.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
*/
3939
public final class SignedJwt {
4040
private static final Pattern JWT_PATTERN = Pattern
41-
.compile("([a-zA-Z0-9/=+]+)\\.([a-zA-Z0-9/=+]+)\\.([a-zA-Z0-9_\\-/=+]*)");
41+
.compile("([a-zA-Z0-9-_=]+)\\.([a-zA-Z0-9-_=]+)\\.([a-zA-Z0-9-_=]*)");
4242
private static final Base64.Decoder URL_DECODER = Base64.getUrlDecoder();
4343
private static final Base64.Encoder URL_ENCODER = Base64.getUrlEncoder().withoutPadding();
4444

security/jwt/src/test/java/io/helidon/security/jwt/SignedJwtTest.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import static org.hamcrest.CoreMatchers.notNullValue;
3232
import static org.hamcrest.MatcherAssert.assertThat;
3333
import static org.junit.jupiter.api.Assertions.assertThrows;
34+
import static org.junit.jupiter.api.Assertions.fail;
3435

3536
/**
3637
* Unit test for {@link SignedJwt}.
@@ -44,6 +45,12 @@ public class SignedJwtTest {
4445
private static final String WRONG_TOKEN =
4546
"yJ4NXQjUzI1NiI6IlZjeXl1TVdxSGp4UjRVNmYzOTV3YmhUZXNZRmFaWXFSbDdBbUxjZE5sNXciLCJ4NXQiOiJTdEZFTlFaM2NMNndQaHFxODZnVmJTTG54TkUiLCJraWQiOiJTSUdOSU5HX0tFWSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJIU01BcHAtY2xpZW50X0FQUElEIiwidXNlci50ZW5hbnQubmFtZSI6ImlkY3MtNzNmYTNlZDY5ZTgxNDFhN2I5MDFmYWY3Zjg3M2U3OGUiLCJzdWJfbWFwcGluZ2F0dHIiOiJ1c2VyTmFtZSIsImlzcyI6Imh0dHBzOlwvXC9pZGVudGl0eS5vcmFjbGVjbG91ZC5jb21cLyIsInRva190eXBlIjoiQVQiLCJjbGllbnRfaWQiOiJIU01BcHAtY2xpZW50X0FQUElEIiwiYXVkIjoiaHR0cDpcL1wvc2NhMDBjangudXMub3JhY2xlLmNvbTo3Nzc3Iiwic3ViX3R5cGUiOiJjbGllbnQiLCJzY29wZSI6InVybjpvcGM6cmVzb3VyY2U6Y29uc3VtZXI6OmFsbCIsImNsaWVudF90ZW5hbnRuYW1lIjoiaWRjcy03M2ZhM2VkNjllODE0MWE3YjkwMWZhZjdmODczZTc4ZSIsImV4cCI6MTU1MDU5NTk0MiwiaWF0IjoxNTUwNTA5NTQyLCJ0ZW5hbnRfaXNzIjoiaHR0cHM6XC9cL2lkY3MtNzNmYTNlZDY5ZTgxNDFhN2I5MDFmYWY3Zjg3M2U3OGUuaWRlbnRpdHkuYzlkZXYxLm9jOXFhZGV2LmNvbSIsImNsaWVudF9ndWlkIjoiN2JmZDM3MjM1ZGY3NDVjNDg5ZjYxZDM1ZTYzZGQ4ZmUiLCJjbGllbnRfbmFtZSI6IkhTTUFwcC1jbGllbnQiLCJ0ZW5hbnQiOiJpZGNzLTczZmEzZWQ2OWU4MTQxYTdiOTAxZmFmN2Y4NzNlNzhlIiwianRpIjoiYzRkNjlhZjUtOGQ4OC00N2Q2LTkzMDctN2RjMmI3NWY4MDQyIn0.ZsngUzzso_sW6rMg3jB-lueiC2sknIDRlgvjumMjp5rRSdLux2X4XZIm2Oa15JbcrnC6I4sgqB0xU1Wte-TW4hbBDLFhaJKYKiNaHBE0L7J73ZK7ITg7dORKkyjLrofGt0m8Rse1OlE9AWevz-l27gtQMO_mctGfHri2BxiMbSN1HwOjWW3kGoqPgCJZJfh2TiFlocEpsXDH4qB1qwhuIoT91gw3kIJlQov0_a9uGEepMU_RWMRjVZCIvuV2hPq_mdeWy2IhkHPxq422CLZ9MDOfbv8F6dY6DralCH4mmKbGM3dbqpZokWQxXG7LG9vWX1PFWw0N9clYHJ4QqBJ4pA";
4647

48+
private static final String BASE64URL_TOKEN =
49+
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlF6QkNNRE0xUVRJMk1qUkZNVEZETkRCRFJUWXdSa1U0UkRkRU16VTVSVGN3TkRSQk5qaENOUSJ9.ewogICJpc3MiOiAidGVzdCIsCiAgImF1ZCI6IFsKICAgICJPQUFDbGllbnR0ZXN0IiwKICAgICJ0ZXN0IgogIF0sCiAgImV4cCI6IDE2NDA0NDU5ODQsCiAgImp0aSI6ICJnamlVOU51UFV5WTZDelVlLUdZS3ZRIiwKICAiaWF0IjogMTYzNzgxNzk4NCwKICAic3ViIjogIk9BQUFkbWludGVzdCIsCiAgImNsaWVudCI6ICJPQUFDbGllbnR0ZXN0IiwKICAic2NvcGUiOiBbCiAgICAib3BlbmlkIgogIF0sCiAgImRvbWFpbiI6ICJPQUFEb21haW50ZXN0IiwKICAiZ3JhbnQiOiAiQVVUSE9SSVpBVElPTl9DT0RFIiwKICAiZ3JvdXBzIjogWwogICAgIk9BQS1BZG1pbi1Sb2xldGVzdCIKICBdLAogICJhcHBJZCI6ICJ0ZXN0IiwKICAic3RhdGljQXR0ciI6ICJDdXN0b21WYWx1ZSIsCiAgInNlc3Npb25JZCI6ICJ0ZXN0LXRlc3QtNDk3Mi10ZXN0LTFkOTJkMDlmZGIxZnxsZUlnVjZwSWwxZEo0M3h4d010NHY2YldVcTVBRm1obDhabVNoM3RiT2lzPSIsCiAgImFwcGxpY2F0aW9uSWQiOiAidGVzdCIsCiAgIm5vbmNlIjogInRlc3QtYjU3MC00MzUwLXRlc3QtZDAwNWJmNDIyYTNhIiwKICAibWRjX3Nzb19saW5rIjogIjI2NWM3LXRlc3QwMDUyLn5-VXNlcklkZW50aXR5U3RvcmUxIiwKICAicmVzU3J2QXR0ciI6ICJSRVNPVVJDRUNPTlNUIgp9.hk4WiDJQrEw5GHvls0qG4C56_Hv-vSrnDWN5m_ikfmlPfJjDaNRUU-phuOb2YhQs_zzSxYmIyWcph4DUKMNF6akx_qHuJnbm7wX5Ps18gNzFM6d9WSalUUL1oILKvutpsHKzI4TVgmfO6DmeIgxxPLXyozRQWcsJPcDMuSDiE06Li4LhjKhzXgj1jpnDcaMttF_EQqiIv3CHWLodXs-WLS_meBQXrdyZPH_O805E3wFTWyFxAUSt2KsevgiHKUxGZtGBwCiOwS5gMfR1aJPuXY4YhkONFDX19Z-DShImLcdPn3yrt1dGJn145TNjftiOBHOkpRmlNHmI0lI-HIgozg";
50+
51+
private static final String NO_SIGNATURE_TOKEN =
52+
"eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.ewogICJpc3MiOiAidGVzdCIsCiAgImF1ZCI6IFsKICAgICJPQUFDbGllbnR0ZXN0IiwKICAgICJ0ZXN0IgogIF0sCiAgImV4cCI6IDE2NDA0NDU5ODQsCiAgImp0aSI6ICJnamlVOU51UFV5WTZDelVlLUdZS3ZRIiwKICAiaWF0IjogMTYzNzgxNzk4NCwKICAic3ViIjogIk9BQUFkbWludGVzdCIsCiAgImNsaWVudCI6ICJPQUFDbGllbnR0ZXN0IiwKICAic2NvcGUiOiBbCiAgICAib3BlbmlkIgogIF0sCiAgImRvbWFpbiI6ICJPQUFEb21haW50ZXN0IiwKICAiZ3JhbnQiOiAiQVVUSE9SSVpBVElPTl9DT0RFIiwKICAiZ3JvdXBzIjogWwogICAgIk9BQS1BZG1pbi1Sb2xldGVzdCIKICBdLAogICJhcHBJZCI6ICJ0ZXN0IiwKICAic3RhdGljQXR0ciI6ICJDdXN0b21WYWx1ZSIsCiAgInNlc3Npb25JZCI6ICJ0ZXN0LXRlc3QtNDk3Mi10ZXN0LTFkOTJkMDlmZGIxZnxsZUlnVjZwSWwxZEo0M3h4d010NHY2YldVcTVBRm1obDhabVNoM3RiT2lzPSIsCiAgImFwcGxpY2F0aW9uSWQiOiAidGVzdCIsCiAgIm5vbmNlIjogInRlc3QtYjU3MC00MzUwLXRlc3QtZDAwNWJmNDIyYTNhIiwKICAibWRjX3Nzb19saW5rIjogIjI2NWM3LXRlc3QwMDUyLn5-VXNlcklkZW50aXR5U3RvcmUxIiwKICAicmVzU3J2QXR0ciI6ICJSRVNPVVJDRUNPTlNUIgp9.";
53+
4754
private static JwkKeys auth0Keys;
4855
private static JwkKeys customKeys;
4956

@@ -69,6 +76,48 @@ public void testParsing() {
6976
assertThat(signedJwt.tokenContent(), is(AUTH_0_TOKEN));
7077
}
7178

79+
@Test
80+
public void testParsingBase64URL() {
81+
SignedJwt signedJwt = SignedJwt.parseToken(BASE64URL_TOKEN);
82+
83+
assertThat(signedJwt.headerJson(), notNullValue());
84+
assertThat(signedJwt.payloadJson(), notNullValue());
85+
assertThat(signedJwt.getSignature(), notNullValue());
86+
assertThat(signedJwt.getSignedBytes(), notNullValue());
87+
assertThat(signedJwt.tokenContent(), is(BASE64URL_TOKEN));
88+
}
89+
90+
@Test
91+
public void testParsingInvalidEncodingOnTokenParts() {
92+
String[][] tokens = {
93+
{"header", "eyJhbGciOiJIUzI1+NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"},
94+
{"payload", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9+lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"},
95+
{"signature", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV/adQssw5c"}
96+
};
97+
for (int i=0; i < tokens.length; i++) {
98+
try {
99+
SignedJwt.parseToken(tokens[i][1]);
100+
fail("Parsing should have failed as the token " + tokens[i][0] + " is incorrectly encoded");
101+
} catch (JwtException t) {
102+
}
103+
}
104+
}
105+
106+
@Test
107+
public void testParsingNoSignature() {
108+
SignedJwt signedJwt = SignedJwt.parseToken(NO_SIGNATURE_TOKEN);
109+
110+
assertThat(signedJwt.getSignature(), notNullValue());
111+
assertThat(signedJwt.getSignedBytes(), notNullValue());
112+
assertThat(signedJwt.getSignature(), is(new byte[0]));
113+
assertThat(signedJwt.tokenContent(), is(NO_SIGNATURE_TOKEN));
114+
115+
Errors errors = signedJwt.verifySignature(null, Jwk.NONE_JWK);
116+
assertThat(errors, notNullValue());
117+
errors.log(LOGGER);
118+
errors.checkValid();
119+
}
120+
72121
@Test
73122
public void testVerify() {
74123
SignedJwt signedJwt = SignedJwt.parseToken(AUTH_0_TOKEN);

0 commit comments

Comments
 (0)