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

Add DefaultJwtParser functionality to parse JWSs with empty body. #540

Merged
merged 6 commits into from
Jun 8, 2020

Conversation

siebenfarben
Copy link
Contributor

@siebenfarben siebenfarben commented Dec 16, 2019

Context
We are currently implementing RFC 8555 which requires requests authenticated through JWS object payloads.
It suggests using signed POST-AS-GET requests with empty JWS bodies for authenticating GET requests. When using jjwt library for the JWS handling we found that empty bodies are disallowed quite explicitly in DefaultJwtParser when parsing JWSs.

Solution
We added flag allowEmptyBody, alongside JwtParserBuilder fields and methods, to the DefaultJwtParser. This way the empty body check can still be used if required and allowing them is an intentional call.

To successfully parse empty-body JWS objects the parsed payload is accepted in a null-safe way (DefaultJWTParser lines 300 & 324). When proactively checking for and mapping json in line 335 we added a simple empty check for the payload.

@coveralls
Copy link

coveralls commented Dec 16, 2019

Coverage Status

Coverage remained the same at 100.0% when pulling 7b379e6 on siebenfarben:master into eadf0ce on jwtk:master.

Copy link
Contributor

@lhazlewood lhazlewood left a comment

Choose a reason for hiding this comment

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

@siebenfarben thanks very much for the PR and starting a discussion. I've made some comments - let me know your thoughts.

@lhazlewood
Copy link
Contributor

cc @bdemers and @dogeared in case you guys want to chime in

…. Set payloadRequired true for each require*() method in JwtParser and JwtParserBuilder.
@siebenfarben
Copy link
Contributor Author

Hi @lhazlewood
please have a look at the updated PR. Thanks again for your comments!

@bdemers
Copy link
Member

bdemers commented Dec 17, 2019

Great stuff @siebenfarben !

@@ -293,7 +303,7 @@ public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException,
base64UrlEncodedDigest = sb.toString();
}

if (base64UrlEncodedPayload == null) {
if (base64UrlEncodedPayload == null && payloadRequired) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I was thinking about triggering exceptions due to payloadRequired() late last night and how an exception might manifest for the user.

Let's say someone configures requireSubject("foo") and then there isn't a payload. The exception they'll see is a generic MalformedJwtException with a message "JWT string '<whatever>' is missing a body/payload", and doesn't explain at all why the JWT is required to have a payload.

To me, this seems to be undesirable. If you think about it, in practice, almost no one really cares that there is a payload or not. What they really care about is if something in the payload exists and/or matches an expectation. And we already have support for enforcing and communicating those things via the other require* methods in the class.

(Also FWIW, I don't think MalformedJwtException is correct here - the JWT isn't malformed - it's just that expectation/validation requirements have failed, so I think we'd have to throw another exception - probably UnsupportedJwtException, and that's if we throw at all...)

Which brings me to my next point: do we need this check at all?

What if we didn't have a payloadRequired check at all and just let the empty string default as done on line 330 in this PR below? The other require* methods would still fail with a meaningful/descriptive exception as is more desirable.

Would there be any problems? Would any of the existing many tests in the project fail? That would tell us a lot.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. 'Malformed' is certainly not the correct wording in that case. It's more an unmet requirement the callers asked for themselves.
All I can say from during the implementation - no tests fail if this check just goes away. The only thing that needs to be added would be the isEmpty() check for the payload below.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok - in this case, I don't think we need the concept of payloadRequired at all and just keep the isEmpty() check.

Copy link
Contributor

@lhazlewood lhazlewood left a comment

Choose a reason for hiding this comment

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

@siebenfarben thanks for going through this process with us. I think we can wrap this up now based on the comments below. After your changes, I'll review once more and then I think we'll be able to merge. Thanks!

@@ -293,7 +303,7 @@ public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException,
base64UrlEncodedDigest = sb.toString();
}

if (base64UrlEncodedPayload == null) {
if (base64UrlEncodedPayload == null && payloadRequired) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok - in this case, I don't think we need the concept of payloadRequired at all and just keep the isEmpty() check.

@siebenfarben
Copy link
Contributor Author

Hi @lhazlewood, please have a look at the updated request. :) Small heads-up: I will from now on be on vacation without my laptop. Happy holidays! Best, @siebenfarben

@siebenfarben
Copy link
Contributor Author

I'm back - happy new year!
Are the changes now in state that can be merged? :)

@lhazlewood
Copy link
Contributor

Hi @siebenfarben - apologies for the long delay! This was lost in the cracks 😞 . Merging now!

@lhazlewood lhazlewood merged commit 2b00ed1 into jwtk:master Jun 8, 2020
@lhazlewood lhazlewood added this to the 0.11.2 milestone Jun 8, 2020
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.

4 participants