Handle parsed JSON JWKS input with string keys #348
When decoded JSON is passed to the JWK.import, there are difficult to diagnose failures that occur.
Since the goal of JWKS is to support loading of json files, we should cleanly support string keys as that is the natural input to these methods.
This PR creates support for directly parsed JSON with string keys.
I have copied below the spec output without the fixes I added. You can see from the failures that the errors are very difficult to understand when all that has happened is the keys were missed.
For instance, "could not find public key" is confusing because debugging shows a perfect match between your JWK and the JWT kid. It's simply the fact that the key is a string and this is not expected.
JWT::DecodeError: Could not find public key for kid 3240eb23aa4f72d26b1b1b534fee4c58c68a51af73b18acedd1e697a775a67fe # ./lib/jwt/jwk/key_finder.rb:17:in `key_for' # ./lib/jwt/decode.rb:37:in `verify_signature' # ./lib/jwt/decode.rb:26:in `decode_segments' # ./lib/jwt.rb:28:in `decode' # ./spec/jwk/decode_with_jwk_spec.rb:71:in `block (4 levels) in <top (required)>'
expected JWT::JWKError with "Key format is invalid for RSA", got #<NoMethodError: undefined method `tr' for nil:NilClass> with backtrace: # ./lib/jwt/jwk/rsa.rb:43:in `import' # ./spec/jwk/rsa_spec.rb:59:in `block (3 levels) in <top (required)>' # ./spec/jwk/rsa_spec.rb:83:in `block (5 levels) in <top (required)>' # ./spec/jwk/rsa_spec.rb:83:in `block (4 levels) in <top (required)>' # ./spec/jwk/rsa_spec.rb:83:in `block (4 levels) in <top (required)>'
Failure/Error: imported_key.set_key(OpenSSL::BN.new(::Base64.urlsafe_decode64(jwk_data[:n]), BINARY), OpenSSL::BN.new(::Base64.urlsafe_decode64(jwk_data[:e]), BINARY), nil) NoMethodError: undefined method `tr' for nil:NilClass # ./lib/jwt/jwk/rsa.rb:43:in `import' # ./spec/jwk/rsa_spec.rb:59:in `block (3 levels) in <top (required)>' # ./spec/jwk/rsa_spec.rb:74:in `block (4 levels) in <top (required)>'
Linking to #95 also because it is somewhat related to the string/symbol issue here.
The source of this problem could be tied back to the README example which uses
Hello, @martinemde! This is your first Pull Request that will be reviewed by SourceLevel, an automatic Code Review service. It will leave comments on this diff with potential issues and style violations found in the code as you push new commits. You can also see all the issues found on this Pull Request on its review page. Please check our documentation for more information.
Hi, this feature is great. It's always a hassle to ensure the keys are the correct type.
Im wondering if it would be a good idea to transform the keys into either strings or symbols before using the hash, that would remove the need to always check for both key types whenever the values are accessed.
I think most of the hash lookups are during import so it wouldn't buy us much.
The example in the readme for loading JWK indicates that caching should be performed inside the loader (before this import step). Unless I'm mistaken, after importing, a single key is grabbed from the key set and used to check the signature, then the entire thing is discarded.
Given just how very fast and lightweight 2 hash lookups is compared to deep copying a parsed json object of unknown size, I'd recommend we don't convert the input in any way.