Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert Encoding/Decoding changes for better compatibility #117

Merged
merged 10 commits into from Nov 6, 2021

Conversation

ajermaky
Copy link
Contributor

This is a small revert to the optimizations made to the encoding/decoding in #33.

While technically JWTs should not have padded characters in Base64 URL encoding, it seems like not every provider may follow this construct, specifically AWS Cognito as seen in #92.

While the change initially was made to have better optimization, it has left compatibility issues, forcing dependencies to stay on v3.2.1 until an update occurs. Thus the proposal is to simply undo the changes made in that section of code, and create a new ticket to better optimize this section.

@ajermaky
Copy link
Contributor Author

go test --bench=Bench --run=NONE .

Before Change:
goos: linux goarch: amd64 pkg: github.com/golang-jwt/jwt/v4 BenchmarkECDSAParsing/Basic_ES256-16 643087 1725 ns/op 1224 B/op 39 allocs/op BenchmarkECDSAParsing/Basic_ES384-16 1474 761221 ns/op 1737768 B/op 14375 allocs/op BenchmarkECDSAParsing/Basic_ES512-16 6580 167854 ns/op 1968 B/op 44 allocs/op BenchmarkECDSAParsing/basic_ES256_invalid:_foo_=>_bar-16 694071 1691 ns/op 1224 B/op 39 allocs/op BenchmarkECDSASigning/Basic_ES256-16 330040 3899 ns/op 3871 B/op 58 allocs/op BenchmarkECDSASigning/Basic_ES256/sign-only-16 44526 27040 ns/op 2946 B/op 37 allocs/op BenchmarkECDSASigning/Basic_ES384-16 1507 800376 ns/op 1751594 B/op 14474 allocs/op BenchmarkECDSASigning/Basic_ES384/sign-only-16 248 4833601 ns/op 1742866 B/op 14392 allocs/op BenchmarkECDSASigning/Basic_ES512-16 5558 182327 ns/op 9157 B/op 87 allocs/op BenchmarkECDSASigning/Basic_ES512/sign-only-16 772 1551958 ns/op 8114 B/op 66 allocs/op BenchmarkECDSASigning/basic_ES256_invalid:_foo_=>_bar-16 295987 3931 ns/op 3871 B/op 58 allocs/op BenchmarkHS256Signing-16 1916628 630.9 ns/op 1554 B/op 30 allocs/op BenchmarkHS384Signing-16 1563625 757.1 ns/op 1939 B/op 30 allocs/op BenchmarkHS512Signing-16 1500824 779.9 ns/op 2035 B/op 30 allocs/op BenchmarkParseUnverified/map_claims-16 1519772 797.8 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#01-16 1350411 895.9 ns/op 2328 B/op 41 allocs/op BenchmarkParseUnverified/map_claims#02-16 1339419 903.0 ns/op 2327 B/op 41 allocs/op BenchmarkParseUnverified/map_claims#03-16 1000000 1004 ns/op 2431 B/op 46 allocs/op BenchmarkParseUnverified/map_claims#04-16 1486888 803.0 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#05-16 1501429 802.0 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#06-16 1473259 818.7 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#07-16 1459118 822.5 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#08-16 1472215 822.2 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#09-16 1484450 815.4 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#10-16 1477605 828.9 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#11-16 1479944 812.6 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#12-16 1476196 816.8 ns/op 2192 B/op 35 allocs/op BenchmarkParseUnverified/standard_claims-16 1412841 841.5 ns/op 2215 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#13-16 1314297 918.4 ns/op 2328 B/op 41 allocs/op BenchmarkParseUnverified/map_claims#14-16 1307355 932.0 ns/op 2328 B/op 41 allocs/op BenchmarkParseUnverified/map_claims#15-16 1000000 1034 ns/op 2432 B/op 46 allocs/op BenchmarkParseUnverified/map_claims#16-16 1282791 939.1 ns/op 2328 B/op 41 allocs/op BenchmarkRSAParsing-16 194726 5517 ns/op 9611 B/op 93 allocs/op BenchmarkRS256Signing-16 8001 150577 ns/op 32934 B/op 136 allocs/op BenchmarkRS384Signing-16 7653 150839 ns/op 33101 B/op 136 allocs/op BenchmarkRS512Signing-16 7750 154075 ns/op 33193 B/op 137 allocs/op PASS ok github.com/golang-jwt/jwt/v4 59.658s
With Change:
goos: linux goarch: amd64 pkg: github.com/golang-jwt/jwt/v4 BenchmarkECDSAParsing/Basic_ES256-16 624736 1731 ns/op 1224 B/op 39 allocs/op BenchmarkECDSAParsing/Basic_ES384-16 1466 804266 ns/op 1737522 B/op 14373 allocs/op BenchmarkECDSAParsing/Basic_ES512-16 5895 178290 ns/op 1968 B/op 44 allocs/op BenchmarkECDSAParsing/basic_ES256_invalid:_foo_=>_bar-16 726552 1751 ns/op 1224 B/op 39 allocs/op BenchmarkECDSASigning/Basic_ES256-16 272566 4517 ns/op 3946 B/op 61 allocs/op BenchmarkECDSASigning/Basic_ES256/sign-only-16 45267 27159 ns/op 2970 B/op 38 allocs/op BenchmarkECDSASigning/Basic_ES384-16 1388 814339 ns/op 1750131 B/op 14465 allocs/op BenchmarkECDSASigning/Basic_ES384/sign-only-16 244 4876130 ns/op 1746570 B/op 14422 allocs/op BenchmarkECDSASigning/Basic_ES512-16 6546 188880 ns/op 9232 B/op 90 allocs/op BenchmarkECDSASigning/Basic_ES512/sign-only-16 739 1604532 ns/op 8138 B/op 67 allocs/op BenchmarkECDSASigning/basic_ES256_invalid:_foo_=>_bar-16 310046 4055 ns/op 3947 B/op 61 allocs/op BenchmarkHS256Signing-16 1865044 673.0 ns/op 1626 B/op 33 allocs/op BenchmarkHS384Signing-16 1482190 817.9 ns/op 2011 B/op 33 allocs/op BenchmarkHS512Signing-16 1302980 952.1 ns/op 2107 B/op 33 allocs/op BenchmarkParseUnverified/map_claims-16 1407746 902.8 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/map_claims#01-16 1223947 951.4 ns/op 2328 B/op 41 allocs/op BenchmarkParseUnverified/map_claims#02-16 1288410 919.1 ns/op 2327 B/op 41 allocs/op BenchmarkParseUnverified/map_claims#03-16 1000000 1067 ns/op 2495 B/op 48 allocs/op BenchmarkParseUnverified/map_claims#04-16 1441771 837.4 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/map_claims#05-16 1353867 897.7 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/map_claims#06-16 1407392 828.7 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/map_claims#07-16 1460398 835.1 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/map_claims#08-16 1432087 853.3 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/map_claims#09-16 1344019 864.0 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/map_claims#10-16 1391701 881.8 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/map_claims#11-16 1351614 877.9 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/map_claims#12-16 1341878 917.2 ns/op 2216 B/op 37 allocs/op BenchmarkParseUnverified/standard_claims-16 1349334 856.1 ns/op 2215 B/op 35 allocs/op BenchmarkParseUnverified/map_claims#13-16 1221648 955.7 ns/op 2328 B/op 41 allocs/op BenchmarkParseUnverified/map_claims#14-16 1295176 930.1 ns/op 2328 B/op 41 allocs/op BenchmarkParseUnverified/map_claims#15-16 1000000 1079 ns/op 2496 B/op 48 allocs/op BenchmarkParseUnverified/map_claims#16-16 1314368 929.9 ns/op 2328 B/op 41 allocs/op BenchmarkRSAParsing-16 213618 5737 ns/op 9611 B/op 93 allocs/op BenchmarkRS256Signing-16 7338 152081 ns/op 32993 B/op 139 allocs/op BenchmarkRS384Signing-16 7332 157187 ns/op 33158 B/op 139 allocs/op BenchmarkRS512Signing-16 7813 156765 ns/op 33256 B/op 140 allocs/op PASS ok github.com/golang-jwt/jwt/v4 61.993s

@oxisto
Copy link
Collaborator

oxisto commented Oct 30, 2021

Just to understand it correctly: is only the decoding part problematic or also the encoding part? In my opinion we should definitely not promote the creation of invalid JWTs. I am still torn about whether we should accept malformed tokens or not - or at least have it configurable. Unfortunately, I did not have time to look at the AWS Problem in more detail yet.

@ajermaky
Copy link
Contributor Author

ajermaky commented Oct 31, 2021

Hi @oxisto, the issue here is on the decoding part, so we can definitely keep the Encoding section as is -> just was not sure if we wanted to make the encoding/decoding utilize different encodings. I just updated it to undo the encoding change, and instead added a check to switch between decoding schemes based on presence of padded characters - similar to what was there before, except not adding extra characters for each token.

To drill down into the specific issue -> The AWS ELB guide indicates that they will provide tokens in JWT that is base64 url encoded with padding at the end.

With regards to accepting malformed tokens, we definitely should have it be configurable if possible, but from initial inspection, don't see a way of doing it without introducing major changes (which probably requires a re-design of the package), or introducing global variables. Hence why a suggestion to allow compatibility for now until we have a better solution down the line.

Based on the update, I re-ran the benchmark, seems like its more similar to main's benchmarks:

Before Change:
goos: linux
goarch: amd64
pkg: github.com/golang-jwt/jwt/v4
cpu: AMD Ryzen 7 3700X 8-Core Processor             
BenchmarkECDSAParsing/Basic_ES256-16              667090              1728 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSAParsing/Basic_ES384-16                1554            806709 ns/op         1737686 B/op      14374 allocs/op
BenchmarkECDSAParsing/Basic_ES512-16                6584            185750 ns/op            1969 B/op         44 allocs/op
BenchmarkECDSAParsing/basic_ES256_invalid:_foo_=>_bar-16                  747355              1779 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSASigning/Basic_ES256-16                                      252723              3992 ns/op            3871 B/op         58 allocs/op
BenchmarkECDSASigning/Basic_ES256/sign-only-16                             43102             27133 ns/op            2946 B/op         37 allocs/op
BenchmarkECDSASigning/Basic_ES384-16                                        1450            821664 ns/op         1751114 B/op      14470 allocs/op
BenchmarkECDSASigning/Basic_ES384/sign-only-16                               243           4826682 ns/op         1748243 B/op      14434 allocs/op
BenchmarkECDSASigning/Basic_ES512-16                                        5595            186453 ns/op            9156 B/op         87 allocs/op
BenchmarkECDSASigning/Basic_ES512/sign-only-16                               770           1554861 ns/op            8114 B/op         66 allocs/op
BenchmarkECDSASigning/basic_ES256_invalid:_foo_=>_bar-16                  290146              4123 ns/op            3871 B/op         58 allocs/op
BenchmarkHS256Signing-16                                                         1769683               730.0 ns/op          1554 B/op         30 allocs/op
BenchmarkHS384Signing-16                                                         1571790               782.7 ns/op          1939 B/op         30 allocs/op
BenchmarkHS512Signing-16                                                         1514004               833.2 ns/op          2035 B/op         30 allocs/op
BenchmarkParseUnverified/map_claims-16                                           1492278               802.7 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#01-16                                        1334053               895.1 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#02-16                                        1292264               909.7 ns/op          2327 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#03-16                                        1000000              1026 ns/op            2431 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#04-16                                        1531126               806.6 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#05-16                                        1475558               788.7 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#06-16                                        1515386               788.9 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#07-16                                        1472016               801.0 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#08-16                                        1489172               801.5 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#09-16                                        1491278               801.7 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#10-16                                        1520398               797.4 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#11-16                                        1508778               787.6 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#12-16                                        1498472               800.5 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/standard_claims-16                                      1437022               838.1 ns/op          2215 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#13-16                                        1327017               903.9 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#14-16                                        1325744               913.4 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#15-16                                        1000000              1005 ns/op            2432 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#16-16                                        1331464               896.9 ns/op          2328 B/op         41 allocs/op
BenchmarkRSAParsing-16                                                            220582              5701 ns/op            9611 B/op         93 allocs/op
BenchmarkRS256Signing-16                                                            7120            150940 ns/op           32923 B/op        136 allocs/op
BenchmarkRS384Signing-16                                                            7988            153745 ns/op           33089 B/op        136 allocs/op
BenchmarkRS512Signing-16                                                            7467            156634 ns/op           33160 B/op        137 allocs/op
PASS
ok      github.com/golang-jwt/jwt/v4    59.874s


After Change:
goos: linux
goarch: amd64
pkg: github.com/golang-jwt/jwt/v4
BenchmarkECDSAParsing/Basic_ES256-16              641659              1777 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSAParsing/Basic_ES384-16                1448            790558 ns/op         1737619 B/op      14374 allocs/op
BenchmarkECDSAParsing/Basic_ES512-16                6384            167321 ns/op            1969 B/op         44 allocs/op
BenchmarkECDSAParsing/basic_ES256_invalid:_foo_=>_bar-16                  741724              1711 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSASigning/Basic_ES256-16                                      311395              3988 ns/op            3870 B/op         58 allocs/op
BenchmarkECDSASigning/Basic_ES256/sign-only-16                             43597             26778 ns/op            2946 B/op         37 allocs/op
BenchmarkECDSASigning/Basic_ES384-16                                        1563            795940 ns/op         1751560 B/op      14474 allocs/op
BenchmarkECDSASigning/Basic_ES384/sign-only-16                               248           4800944 ns/op         1747932 B/op      14432 allocs/op
BenchmarkECDSASigning/Basic_ES512-16                                        5529            184012 ns/op            9156 B/op         87 allocs/op
BenchmarkECDSASigning/Basic_ES512/sign-only-16                               764           1576447 ns/op            8114 B/op         66 allocs/op
BenchmarkECDSASigning/basic_ES256_invalid:_foo_=>_bar-16                  302439              3928 ns/op            3871 B/op         58 allocs/op
BenchmarkHS256Signing-16                                                         1952811               624.5 ns/op          1554 B/op         30 allocs/op
BenchmarkHS384Signing-16                                                         1614547               745.4 ns/op          1939 B/op         30 allocs/op
BenchmarkHS512Signing-16                                                         1559641               770.7 ns/op          2035 B/op         30 allocs/op
BenchmarkParseUnverified/map_claims-16                                           1546458               768.9 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#01-16                                        1479475               798.2 ns/op          2215 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#02-16                                        1351315               894.5 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#03-16                                        1333856               891.1 ns/op          2327 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#04-16                                        1000000              1002 ns/op            2431 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#05-16                                        1516365               791.0 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#06-16                                        1522262               796.6 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#07-16                                        1514139               789.3 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#08-16                                        1498621               788.0 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#09-16                                        1504119               787.4 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#10-16                                        1507728               794.4 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#11-16                                        1508684               809.3 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#12-16                                        1496773               797.1 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#13-16                                        1494387               800.6 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/standard_claims-16                                      1404908               851.0 ns/op          2215 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#14-16                                        1325373               904.0 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#15-16                                        1313220               922.9 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#16-16                                        1000000              1029 ns/op            2432 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#17-16                                        1318063               908.3 ns/op          2328 B/op         41 allocs/op
BenchmarkRSAParsing-16                                                            202165              5638 ns/op            9611 B/op         93 allocs/op
BenchmarkRS256Signing-16                                                            6914            151441 ns/op           32935 B/op        136 allocs/op
BenchmarkRS384Signing-16                                                            7227            153647 ns/op           33107 B/op        137 allocs/op
BenchmarkRS512Signing-16                                                            7382            155843 ns/op           33176 B/op        137 allocs/op
PASS
ok      github.com/golang-jwt/jwt/v4    61.252s

@oxisto
Copy link
Collaborator

oxisto commented Oct 31, 2021

Hi @oxisto, the issue here is on the decoding part, so we can definitely keep the Encoding section as is -> just was not sure if we wanted to make the encoding/decoding utilize different encodings. I just updated it to undo the encoding change, and instead added a check to switch between decoding schemes based on presence of padded characters - similar to what was there before, except not adding extra characters for each token.

To drill down into the specific issue -> The AWS ELB guide indicates that they will provide tokens in JWT that is base64 url encoded with padding at the end.

With regards to accepting malformed tokens, we definitely should have it be configurable if possible, but from initial inspection, don't see a way of doing it without introducing major changes (which probably requires a re-design of the package), or introducing global variables. Hence why a suggestion to allow compatibility for now until we have a better solution down the line.

Based on the update, I re-ran the benchmark, seems like its more similar to main's benchmarks:

Before Change:
goos: linux
goarch: amd64
pkg: github.com/golang-jwt/jwt/v4
cpu: AMD Ryzen 7 3700X 8-Core Processor             
BenchmarkECDSAParsing/Basic_ES256-16              667090              1728 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSAParsing/Basic_ES384-16                1554            806709 ns/op         1737686 B/op      14374 allocs/op
BenchmarkECDSAParsing/Basic_ES512-16                6584            185750 ns/op            1969 B/op         44 allocs/op
BenchmarkECDSAParsing/basic_ES256_invalid:_foo_=>_bar-16                  747355              1779 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSASigning/Basic_ES256-16                                      252723              3992 ns/op            3871 B/op         58 allocs/op
BenchmarkECDSASigning/Basic_ES256/sign-only-16                             43102             27133 ns/op            2946 B/op         37 allocs/op
BenchmarkECDSASigning/Basic_ES384-16                                        1450            821664 ns/op         1751114 B/op      14470 allocs/op
BenchmarkECDSASigning/Basic_ES384/sign-only-16                               243           4826682 ns/op         1748243 B/op      14434 allocs/op
BenchmarkECDSASigning/Basic_ES512-16                                        5595            186453 ns/op            9156 B/op         87 allocs/op
BenchmarkECDSASigning/Basic_ES512/sign-only-16                               770           1554861 ns/op            8114 B/op         66 allocs/op
BenchmarkECDSASigning/basic_ES256_invalid:_foo_=>_bar-16                  290146              4123 ns/op            3871 B/op         58 allocs/op
BenchmarkHS256Signing-16                                                         1769683               730.0 ns/op          1554 B/op         30 allocs/op
BenchmarkHS384Signing-16                                                         1571790               782.7 ns/op          1939 B/op         30 allocs/op
BenchmarkHS512Signing-16                                                         1514004               833.2 ns/op          2035 B/op         30 allocs/op
BenchmarkParseUnverified/map_claims-16                                           1492278               802.7 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#01-16                                        1334053               895.1 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#02-16                                        1292264               909.7 ns/op          2327 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#03-16                                        1000000              1026 ns/op            2431 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#04-16                                        1531126               806.6 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#05-16                                        1475558               788.7 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#06-16                                        1515386               788.9 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#07-16                                        1472016               801.0 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#08-16                                        1489172               801.5 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#09-16                                        1491278               801.7 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#10-16                                        1520398               797.4 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#11-16                                        1508778               787.6 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#12-16                                        1498472               800.5 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/standard_claims-16                                      1437022               838.1 ns/op          2215 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#13-16                                        1327017               903.9 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#14-16                                        1325744               913.4 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#15-16                                        1000000              1005 ns/op            2432 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#16-16                                        1331464               896.9 ns/op          2328 B/op         41 allocs/op
BenchmarkRSAParsing-16                                                            220582              5701 ns/op            9611 B/op         93 allocs/op
BenchmarkRS256Signing-16                                                            7120            150940 ns/op           32923 B/op        136 allocs/op
BenchmarkRS384Signing-16                                                            7988            153745 ns/op           33089 B/op        136 allocs/op
BenchmarkRS512Signing-16                                                            7467            156634 ns/op           33160 B/op        137 allocs/op
PASS
ok      github.com/golang-jwt/jwt/v4    59.874s


After Change:
goos: linux
goarch: amd64
pkg: github.com/golang-jwt/jwt/v4
BenchmarkECDSAParsing/Basic_ES256-16              641659              1777 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSAParsing/Basic_ES384-16                1448            790558 ns/op         1737619 B/op      14374 allocs/op
BenchmarkECDSAParsing/Basic_ES512-16                6384            167321 ns/op            1969 B/op         44 allocs/op
BenchmarkECDSAParsing/basic_ES256_invalid:_foo_=>_bar-16                  741724              1711 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSASigning/Basic_ES256-16                                      311395              3988 ns/op            3870 B/op         58 allocs/op
BenchmarkECDSASigning/Basic_ES256/sign-only-16                             43597             26778 ns/op            2946 B/op         37 allocs/op
BenchmarkECDSASigning/Basic_ES384-16                                        1563            795940 ns/op         1751560 B/op      14474 allocs/op
BenchmarkECDSASigning/Basic_ES384/sign-only-16                               248           4800944 ns/op         1747932 B/op      14432 allocs/op
BenchmarkECDSASigning/Basic_ES512-16                                        5529            184012 ns/op            9156 B/op         87 allocs/op
BenchmarkECDSASigning/Basic_ES512/sign-only-16                               764           1576447 ns/op            8114 B/op         66 allocs/op
BenchmarkECDSASigning/basic_ES256_invalid:_foo_=>_bar-16                  302439              3928 ns/op            3871 B/op         58 allocs/op
BenchmarkHS256Signing-16                                                         1952811               624.5 ns/op          1554 B/op         30 allocs/op
BenchmarkHS384Signing-16                                                         1614547               745.4 ns/op          1939 B/op         30 allocs/op
BenchmarkHS512Signing-16                                                         1559641               770.7 ns/op          2035 B/op         30 allocs/op
BenchmarkParseUnverified/map_claims-16                                           1546458               768.9 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#01-16                                        1479475               798.2 ns/op          2215 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#02-16                                        1351315               894.5 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#03-16                                        1333856               891.1 ns/op          2327 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#04-16                                        1000000              1002 ns/op            2431 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#05-16                                        1516365               791.0 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#06-16                                        1522262               796.6 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#07-16                                        1514139               789.3 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#08-16                                        1498621               788.0 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#09-16                                        1504119               787.4 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#10-16                                        1507728               794.4 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#11-16                                        1508684               809.3 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#12-16                                        1496773               797.1 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#13-16                                        1494387               800.6 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/standard_claims-16                                      1404908               851.0 ns/op          2215 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#14-16                                        1325373               904.0 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#15-16                                        1313220               922.9 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#16-16                                        1000000              1029 ns/op            2432 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#17-16                                        1318063               908.3 ns/op          2328 B/op         41 allocs/op
BenchmarkRSAParsing-16                                                            202165              5638 ns/op            9611 B/op         93 allocs/op
BenchmarkRS256Signing-16                                                            6914            151441 ns/op           32935 B/op        136 allocs/op
BenchmarkRS384Signing-16                                                            7227            153647 ns/op           33107 B/op        137 allocs/op
BenchmarkRS512Signing-16                                                            7382            155843 ns/op           33176 B/op        137 allocs/op
PASS
ok      github.com/golang-jwt/jwt/v4    61.252s

Introducing a global variable (for now) would not be an issue I would say. The default could be the "proper" way we currently have on main. In a future overhaul we are likely to de-export DecodeSegment, making it private and properly moving it to the Parser type (since it is the only one using it anyway). We then could move the global variable to a parser option then. This would then also solve potential problems if different go routines want different settings on this variable, which I would argue is definitely a niche use case.

I would assume from a performance standpoint a simple-if-boolean check should be negligible. Maybe the compiler even removes it in optimisation if you never change the default value, not sure.

Any thoughts on this @mfridman @lggomez

@oxisto
Copy link
Collaborator

oxisto commented Oct 31, 2021

To drill down into the specific issue -> The AWS ELB guide indicates that they will provide tokens in JWT that is base64 url encoded with padding at the end.
With regards to accepting malformed tokens, we definitely should have it be configurable if possible, but from initial inspection, don't see a way of doing it without introducing major changes (which probably requires a re-design of the package), or introducing global variables. Hence why a suggestion to allow compatibility for now until we have a better solution down the line.

Just to add on this, this behaviour on AWS's puts us in a though spot. What they claim to be a JWT is simply just not a JWT as defined in JWT/JWS RFC. This leaves implementations such as this in the uncomfortable place to deviate from the standard to support something which should not be there in the first place, just because it is "well used".

Does anyone know anyone close to the AWS ELB team? Maybe we could got this fixed at AWS rather than having everyone bend to their wishes. Not being too hopeful about this though. I have opened an issue on their docs repo, although this is probably not the right place for it: awsdocs/elb-application-load-balancers-user-guide#42.

@ajermaky
Copy link
Contributor Author

Agreed @oxisto that it should be theoretically be fixed on ELB's side, but like you said, not keeping hopes up for now. If they do make they update, then agreed we should remove this. In terms of keeping it scoped to the parser -> seems like the signing methods also utilize this function, so it seemed awkward to somehow pass this to the underlying signing method etc. But if an overhaul is coming, hopefully can be included there (make the signing methods accept the decoded string directly instead of handling the decoding).

I just pushed another update going back to the original proposal in #92 and incorporated @lggomez's recommendation to make it goroutine safe via atomic operations.

Benchmark below:

goos: linux
goarch: amd64
pkg: github.com/golang-jwt/jwt/v4
cpu: AMD Ryzen 7 3700X 8-Core Processor             
BenchmarkECDSAParsing/Basic_ES256-16              659593              1675 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSAParsing/Basic_ES384-16                1570            767038 ns/op         1737722 B/op      14374 allocs/op
BenchmarkECDSAParsing/Basic_ES512-16                6610            168498 ns/op            1968 B/op         44 allocs/op
BenchmarkECDSAParsing/basic_ES256_invalid:_foo_=>_bar-16                  695206              1772 ns/op            1224 B/op         39 allocs/op
BenchmarkECDSASigning/Basic_ES256-16                                      302251              4175 ns/op            3870 B/op         58 allocs/op
BenchmarkECDSASigning/Basic_ES256/sign-only-16                             46093             27051 ns/op            2946 B/op         37 allocs/op
BenchmarkECDSASigning/Basic_ES384-16                                        1500            803619 ns/op         1751347 B/op      14473 allocs/op
BenchmarkECDSASigning/Basic_ES384/sign-only-16                               244           4797638 ns/op         1744971 B/op      14409 allocs/op
BenchmarkECDSASigning/Basic_ES512-16                                        5478            184653 ns/op            9156 B/op         87 allocs/op
BenchmarkECDSASigning/Basic_ES512/sign-only-16                               777           1519325 ns/op            8113 B/op         66 allocs/op
BenchmarkECDSASigning/basic_ES256_invalid:_foo_=>_bar-16                  298452              3907 ns/op            3871 B/op         58 allocs/op
BenchmarkHS256Signing-16                                                         1907900               631.1 ns/op          1554 B/op         30 allocs/op
BenchmarkHS384Signing-16                                                         1535769               758.7 ns/op          1939 B/op         30 allocs/op
BenchmarkHS512Signing-16                                                         1488543               783.7 ns/op          2035 B/op         30 allocs/op
BenchmarkParseUnverified/map_claims-16                                           1508226               792.4 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#01-16                                        1316246               898.6 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#02-16                                        1338156               905.5 ns/op          2327 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#03-16                                        1000000              1056 ns/op            2431 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#04-16                                        1458663               888.9 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#05-16                                        1385847               841.1 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#06-16                                        1461973               820.3 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#07-16                                        1425873               837.1 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#08-16                                        1405864               829.0 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#09-16                                        1457310               895.9 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#10-16                                        1442412               830.2 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#11-16                                        1443147               880.5 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#12-16                                        1429874               888.2 ns/op          2192 B/op         35 allocs/op
BenchmarkParseUnverified/standard_claims-16                                      1377993               882.8 ns/op          2215 B/op         35 allocs/op
BenchmarkParseUnverified/map_claims#13-16                                        1000000              1012 ns/op            2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#14-16                                        1251151               936.1 ns/op          2328 B/op         41 allocs/op
BenchmarkParseUnverified/map_claims#15-16                                         968534              1100 ns/op            2432 B/op         46 allocs/op
BenchmarkParseUnverified/map_claims#16-16                                        1221069               938.7 ns/op          2328 B/op         41 allocs/op
BenchmarkRSAParsing-16                                                            208617              6042 ns/op            9610 B/op         93 allocs/op
BenchmarkRS256Signing-16                                                            7336            153456 ns/op           32932 B/op        136 allocs/op
BenchmarkRS384Signing-16                                                            7827            157871 ns/op           33083 B/op        136 allocs/op
BenchmarkRS512Signing-16                                                            7462            164528 ns/op           33165 B/op        137 allocs/op
PASS
ok      github.com/golang-jwt/jwt/v4    59.415s

Copy link
Collaborator

@oxisto oxisto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good as far as implementation goes I would say, except the minor things I added in the comments. I want to give it another couple of days if we somehow get a response from AWS before we "approve" this.

token.go Outdated Show resolved Hide resolved
token.go Outdated Show resolved Hide resolved
@oxisto
Copy link
Collaborator

oxisto commented Oct 31, 2021

Agreed @oxisto that it should be theoretically be fixed on ELB's side, but like you said, not keeping hopes up for now. If they do make they update, then agreed we should remove this. In terms of keeping it scoped to the parser -> seems like the signing methods also utilize this function, so it seemed awkward to somehow pass this to the underlying signing method etc. But if an overhaul is coming, hopefully can be included there (make the signing methods accept the decoded string directly instead of handling the decoding).

I just pushed another update going back to the original proposal in #92 and incorporated @lggomez's recommendation to make it goroutine safe via atomic operations.

Thanks. I do see some benefit in using the atomic way, however in my opinion, we do not necessarily be really go-routine safe in a way that we would switch between padding on/off in different threads/goroutines and we already have a couple of exported global variables that can be accessed directly, such as TimeFunc and TimePrecision, so from a consistency-approach I would prefer just a global variable like var AllowPadding = false. But that's just my opinion here, maybe we need a maintainer vote on this :D

token.go Outdated Show resolved Hide resolved
@ajermaky
Copy link
Contributor Author

ajermaky commented Oct 31, 2021

Make sense! Since this change should be targeted at specific usecases, enabling/disabling is pretty niche as you stated. I've gone ahead and updated the original atomic method here and updated it to the bool approach (with comment stating it is not go-routine safe) here.

Let me know which approach you all want to take and can update accordingly! Or hopefully ELB team will come back with an update.

@mfridman
Copy link
Member

mfridman commented Nov 3, 2021

Sorry it too so long to reply.

so from a consistency-approach I would prefer just a global variable like var AllowPadding = false.

I agree with this if it is the current state of affairs. Also, I'm not too worried about the performance and quite sympathetic to the issue, because at a previous co. we used AWS and I imagine my old team is in a similar predicament.

It is very unlikely you'll see any movement from AWS to change their implementation.

What if we reverted the original PR as mentioned by OP in this ticket? Is the performance of the old code really that noticeable in production systems?

@oxisto
Copy link
Collaborator

oxisto commented Nov 3, 2021

Sorry it too so long to reply.

so from a consistency-approach I would prefer just a global variable like var AllowPadding = false.

I agree with this if it is the current state of affairs. Also, I'm not too worried about the performance and quite sympathetic to the issue, because at a previous co. we used AWS and I imagine my old team is in a similar predicament.

It is very unlikely you'll see any movement from AWS to change their implementation.

What if we reverted the original PR as mentioned by OP in this ticket? Is the performance of the old code really that noticeable in production systems?

Probably not, however having this switched on/off with the variable as it is now implemented using this PR seems to be a fair compromise.

@@ -435,6 +435,88 @@ func TestParser_ParseUnverified(t *testing.T) {
}
}

var setPaddingTestData = []struct {
name string
tokenString string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we can toss in the example JWT token from this comment?

#92 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just added! Note that I had to add the public key to the repo, added a note where we reference it.

mfridman
mfridman previously approved these changes Nov 4, 2021
Copy link
Collaborator

@oxisto oxisto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor things

parser_test.go Outdated
)

func init() {
// Load public keys
jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub")
jwtTestEC256PublicKey = test.LoadECPublicKeyFromDisk("test/ec256-public.pem")

// Load cognito public key - note there is only a public key for this key pair and should only be used for the
// two test cases below.
exampleCognitoPublicKey = test.LoadECPublicKeyFromDisk("test/exampleCognito-public.pem")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest avoiding a product name here and just name it paddedKey or something

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

parser_test.go Outdated
valid: true,
},
{
name: "Error for padded cognito token with padding disabled",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

parser_test.go Outdated
valid: false,
},
{
name: "Validated padded cognito token with padding enabled",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here avoid the product name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

token.go Outdated
@@ -7,6 +7,14 @@ import (
"time"
)


// DecodePaddingAllowed will switch the codec used for encoding/decoding JWTs respectively. Note that the JWS RFC7515
Copy link
Collaborator

@oxisto oxisto Nov 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is only used for decoding, not encoding

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

parser_test.go Outdated Show resolved Hide resolved
@mfridman mfridman merged commit f4865cd into golang-jwt:main Nov 6, 2021
oxisto pushed a commit to moneszarrugh/jwt that referenced this pull request Feb 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants