Initial implementation of a DPoP proofing mechanism
Resolves #165
This adds the initial structure for handling proof of possession semantics at the application layer.
This PR does not contain any tests, as I would like some initial feedback on this implementation. The basic design assumes that the AbstractDpopTokenValidator class would be extended and the following methods implemented:
::getDpopHeaderValue-- this returns the raw HTTP DPoP header value::getRequestUri-- this returns the HTTP request URI::getRequestMethod-- this returns the HTTP request method
Then, given a @JsonWebToken object, the ::verify method checks that the thumbprint of any access token-bound key:
"cnf": {
"jkt": "<thumbprint>"
}
matches the public key in the request-specific DPoP token (i.e. that the DPoP token is scoped to the request URI and method). This method will throw a ParseException in any of the following cases:
- No key binding in the access token
- No DPoP proofing token available
- Any parse or validation failures of the DPoP token itself
If this seems like a reasonable approach, I will add accompanying tests.
Note: this does not implement jti constraints (which are optional according to DPoP and difficult to support across a cluster of stateless resource servers)
Also note: this makes use of the algorithm defined in authContextInfo.getKeyEncryptionAlgorithm().getAlgorithm(), though it isn't strictly necessary to align those (an identity provider may sign with RSA and a browser may use ECDSA for DPoP proofing -- ephemeral ECDSA keys for use with DPoP are considerably faster to generate in a browser)
DPoP Specification Reference: https://tools.ietf.org/html/draft-fett-oauth-dpop-04
@acoburn Thanks, let me add a few initial comments
Note: this does not implement jti constraints
If the IDP providers will start supporting the DPoP proof verification too then they'd deal with jti.
Perhaps we can also add a protected validateJti method which would return a no op Validatorand then in Quarkus/etc it would be possible to extend and return some custom jti validator...
We can also ship basic validator OOB which will keep a size-constraint Set of jti and keep optimizing it going forward..
Overall, a great start, thanks for spending the time on it. Let me also ping Keycloak colleagues :-)
Hey @acoburn How are you, by the way I've been thinking of having an implementation/jwt-dpop module with your PR eventually making it to that new module. I might give it a go after we release 3.0.0 final, cheers
@sberyozkin that sounds great. I know this PR has gone largely dormant, but I would be happy to help move it forward
Keycloak now supports DPoP as an experimental feature so it is a good time to complete this PR, I'll try to have a look
Hey @acoburn @sberyozkin ,
I hope you are well. I was wondering if there have been any updates regarding the PR? Additionally, are there any significant hurdles or blockers that need to be addressed? Your insights would be greatly appreciated.
I believe this is the correct link to the RFC : https://datatracker.ietf.org/doc/html/rfc9449 Reference implementation in JavaScript/node - https://github.com/search?q=repo%3Apanva%2Fnode-openid-client+dpop&type=commits
@VinodAnandan Hi, preparation for testing it is in #772, but I won't have time to fix it in the very short term in smallrye-jwt. I'll play with it at the quarkus-oidc level and test against Keycloak and once it is done, this PR will be complete, though of course if Aaron @acoburn decides to finalize it sooner, it would be awesome