Giter VIP home page Giter VIP logo

json-jwt's Introduction

JSON::JWT

JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and JSON Web Key) in Ruby

Installation

gem install json-jwt

Resources

Examples

require 'json/jwt'

private_key = OpenSSL::PKey::RSA.new <<-PEM
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAyBKIFSH8dP6bDkGBziB6RXTTfZVTaaNSWNtIzDmgRFi6FbLo
 :
-----END RSA PRIVATE KEY-----
PEM

public_key = OpenSSL::PKey::RSA.new <<-PEM
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyBKIFSH8dP6bDkGBziB6
 :
-----END PUBLIC KEY-----
PEM

# Sign & Encode
claim = {
  iss: 'nov',
  exp: 1.week.from_now,
  nbf: Time.now
}
jws = JSON::JWT.new(claim).sign(private_key, :RS256)
jws.to_s

# Decode & Verify
input = "jwt_header.jwt_claims.jwt_signature"
JSON::JWT.decode(input, public_key)

If you need to get a JWK from jwks_uri of OpenID Connect IdP, you can use JSON::JWK::Set::Fetcher to fetch (& optionally cache) it.

# JWK Set Fetching & Caching
# NOTE: Optionally by setting cache instance, JWKs are cached by kid.
JSON::JWK::Set::Fetcher.cache = Rails.cache

JSON::JWK::Set::Fetcher.fetch(jwks_uri, kid: kid)
# => returns JSON::JWK instance or raise JSON::JWK::Set::KidNotFound

For more details, read Documentation Wiki.

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

Copyright

Copyright (c) 2011 nov matake. See LICENSE for details.

json-jwt's People

Contributors

amatsuda avatar bdewater avatar bmesuere avatar btoews avatar denisenkom avatar dlozano avatar dub357 avatar dukex avatar kintner avatar lucaskanashiro avatar nov avatar ojab avatar sbellity avatar seandilda avatar steved avatar stouset avatar v1nayv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

json-jwt's Issues

Denial of service attack

When parsing JWTs, you symbolize keys. This wouldn't be so bad if the signature was verified first, but since it is not, any user can spam an endpoint with nonsensical JWTs that include (over time) hundreds of thousands or even millions of unique claim keys. These keys get translated to symbols internally, which eat up memory in the interpreter that cannot be garbage collected, since symbols are guaranteed to map uniquely to the same integer ID for the lifetime of the Ruby process.

See this gist for an example of a recent exploit against the Rails stack that involved this type of improper handling.

To fix this, you must not symbolize keys from unsanitized input, and instead store them as strings. The easiest way to maintain API backward compatibility is to then override the JSON::JWT#[] method (inherited from hash) to simply call super key.to_s.

class JSON::JWT < Hash
  def []
    super key.to_s
  end
end

Here's a gist demonstrating the exploit. Note that the "attacker" doesn't need to possess the secret key, nor does the "victim" need to succeed in validating the JWT in order for the attack to succeed.

Changelog

We're currently updating the gem (and experiencing issues) as well as auditing for security purposes. It would be very helpful to have a changelog that calls out the major points for each version without having to dig through all of the commits.

certain malformed JWTs throw nil errors

As of fc84206, the following attempt at decoding malformed JWTs will error in unexpected ways:

irb(main):001:0> JSON::JWT.decode('a.b.c')
NoMethodError: undefined method `with_indifferent_access' for nil:NilClass
        from /Users/cainlevy/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/json-jwt-1.8.0/lib/json/jws.rb:143:in `block in decode_compact_serialized'
        from /Users/cainlevy/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/json-jwt-1.8.0/lib/json/jws.rb:142:in `collect'
        from /Users/cainlevy/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/json-jwt-1.8.0/lib/json/jws.rb:142:in `decode_compact_serialized'
        from /Users/cainlevy/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/json-jwt-1.8.0/lib/json/jwt.rb:85:in `decode_compact_serialized'
        from /Users/cainlevy/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/json-jwt-1.8.0/lib/json/jose.rb:52:in `decode'
        from (irb):1
        from bin/console:14:in `<main>'

This appears to be because MultiJson.decode(nil) will throw an exception, while JSON.decode(nil) will not.

Default `:kid` as thumbprint

I had the idea last night that it might be useful for json-jwt to set up a default :kid for new JWK, then noticed you had pushed changes to add (c1c632d) and then revert (2ca766b) that change at almost exactly the same time that I had the idea. Out of curiosity, can you share what you're thinking?

Support JWS Payloads that are not JSON

Thanks for all the hard work on this project!

Currently json-jwt appears to only support JWS payloads which are valid JSON objects and trying to decode a JWS with a payload that is not a valid JSON object throws an exception.

e.g.

token = "eyJ6a..." # Truncated for readability. Encoded payload is not a valid JSON Obect.

decoded_token   = decoded_token = JSON::JWT.decode token, :skip_verification

Throws json-jwt-1.13.0/lib/json/jose.rb:68:in rescue in decode': Invalid JSON Format (JSON::JWT::InvalidFormat). This exception seems to be thrown when rescuing a JSON::ParserError which originates here:

claims = JSON.parse(claims).with_indifferent_access

The JWS RFC defines the JWS Payload as:

The sequence of octets to be secured -- a.k.a. the message. The payload can contain an arbitrary sequence of octets.

and the example in Section 3.3 says that

(Note that the payload can be any content and need not be a representation of a JSON object.)

Any thoughts on this or the feasibility of supporting JWS payloads of any type?

EC key throwing OpenSSL::PKey::EC::Point::Error

I'm encountering this error when generating id tokens in my app using doorkeeper-openid_connect. I'm using an EC key/512 curve. For some reason, I'm getting an exception at this point in the code: https://github.com/nov/json-jwt/blob/master/lib/json/jwk.rb#L140

The error is: OpenSSL::PKey::EC::Point::Error: invalid encoding

I tried reproducing this directly with a fresh EC key. Here are the steps I took:

  1. Generated a new key pair (Mac 10.11.6, installed openssl through homebrew)
➜  ~ openssl ecparam -name secp521r1 -genkey -out test.pem
➜  ~ openssl ec -in test.pem
read EC key
writing EC key
-----BEGIN EC PRIVATE KEY-----
MIHbAgEBBEEYQPgaKkRZSDaO7vm7tNsT9Nn2PogMwzM0FcYQqS1LKH4SBvm94vTC
dlwf4L+dyOFmP7PgytYIENwRp885GTp3NqAHBgUrgQQAI6GBiQOBhgAEAF04RR8v
jqzJLY4rM7aaQOcLNj7x5dLueq1YP7WXDM0SLo6Sr0odCWdqa0injaMBzzosQ56K
MCZXzCiSmt9YkI3MAA8D8QGG04Q1+ewtrthARff3BgOU9nhUCNVgv36aqcXANkue
vYRayeeFW5UA7dbNPvJrM6ZFH/Wxk1cWHJGl5K/d
-----END EC PRIVATE KEY-----
  1. In Ruby, initialized a new JWK from this private key:
[42] pry(main)> key = "-----BEGIN EC PRIVATE KEY-----\nMIHbAgEBBEEYQPgaKkRZSDaO7vm7tNsT9Nn2PogMwzM0FcYQqS1LKH4SBvm94vTC\ndlwf4L+dyOFmP7PgytYIENwRp885GTp3NqAHBgUrgQQAI6GBiQOBhgAEAF04RR8v\njqzJLY4rM7aaQOcLNj7x5dLueq1YP7WXDM0SLo6Sr0odCWdqa0injaMBzzosQ56K\nMCZXzCiSmt9YkI3MAA8D8QGG04Q1+ewtrthARff3BgOU9nhUCNVgv36aqcXANkue\nvYRayeeFW5UA7dbNPvJrM6ZFH/Wxk1cWHJGl5K/d\n-----END EC PRIVATE KEY-----"; nil
=> nil
[43] pry(main)> pkey = OpenSSL::PKey.read(key)
=> #<OpenSSL::PKey::EC:0x00000009714158>
[44] pry(main)> jwk = JSON::JWK.new(pkey)
=> {"kty"=>:EC,
 "crv"=>:"P-521",
 "x"=>
  "XThFHy-OrMktjisztppA5ws2PvHl0u56rVg_tZcMzRIujpKvSh0JZ2prSKeNowHPOixDnoowJlfMKJKa31iQjcw",
 "y"=>
  "DwPxAYbThDX57C2u2EBF9_cGA5T2eFQI1WC_fpqpxcA2S569hFrJ54VblQDt1s0-8mszpkUf9bGTVxYckaXkr90",
 "d"=>
  "GED4GipEWUg2ju75u7TbE_TZ9j6IDMMzNBXGEKktSyh-Egb5veL0wnZcH-C_ncjhZj-z4MrWCBDcEafPORk6dzY",
 "kid"=>"JjqJwuVmuEXrpHkSpljVnN9zHbUyUT1-cMCHfJId2xM"}
  1. Converted this back to a key, which is what JWS does during signing:
[45] pry(main)> jwk.to_key
OpenSSL::PKey::EC::Point::Error: invalid encoding
from /usr/local/bundle/gems/json-jwt-1.7.2/lib/json/jwk.rb:140:in `initialize'

Is there something wrong with this approach? Or is this a bug in the JWK implementation for EC keys? Maybe something else? I'm at a bit of a loss for how to continue debugging.

Thanks in advance for any help!

Can payload for signing with JWT be a string instead of a json

Hi,
I'm just wondering if there is a way to sign a message as a string?? Like:

payload = 'my string to sign'
signed_message = JSON::JWT.new(payload).sign(my_private_key, :RS256)

instead of:
payload = {
foo: 'my string to sign'
}
Thanks in advance and appreciate your help!

Ed25519 support

It might be needed once self-issued OIDC are used by DID community.

Nimbus JOSE+JWT IV additional character being ignored

I am using Nimbus JOSE+JWT library. If we add ONE extra character to the BASE64URL encoded IV and try decoding the same using Base64Codec.java it yields the same result. The last additional character is being ignored.

`String encodedValue = "e_DQ6gm5gGsGfWnh";
// encodedValue = "e_DQ6gm5gGsGfWnha"
Base64URL encodedIV = new Base64URL(encodedValue);

byte[] out = encodedIV.decode();
// The trailing 'h' does not make a difference to the decoded value

`

Serialization of valid JW* not always valid

JSON supports optional escaping of characters which means that there are multiple representations of the same decoded object.

When JSON::JWT#to_s is called (similarly JSON:JWE#to_s and others) the JSON is re-serialized using ruby's default JSON encoding.

Because re-serializing the JWT is never guaranteed to be bit-perfect identical to the original serialized JSON, but that is depended upon for the signature to be accurate, I recommend that the decode_compact_serialized methods also keep track of the original JWT string, and return it in place of the generated versions if present/appropriate.

Trivial example

jwt = 'e30=.eyJpc3MiOiJodHRwczpcL1wvZXhhbXBsZS5jb21cLyJ9.whatever'
obj = JSON::JWT.decode(jwt, :skip_verification)
obj.to_s
#     "e30.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tLyJ9.whatever"
obj.to_s == jwt
# false

puts Base64.decode64(jwt.split('.')[1])
# {"iss":"https:\/\/example.com\/"}
puts Base64.decode64(obj.to_s.split('.')[1])
# {"iss":"https://example.com/"}
obj.to_h
# {"iss"=>"https://example.com/"}

ECDH-ES support in JWE

Just for curiosity, are there any plans to support 'ECDH-ES' as key encryption algorithm?

"cannot load such file -- json-jwt (LoadError)"

Getting this error:

"/usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require': cannot load such file -- json-jwt (LoadError)"

I'm seeing this in two completely separate environments, one of them running Ruby 2.6.3, and this one illustrated, running 2.5.5.

Am I doing something dumb? thanks!

STR:

gem install json-jwt

output:

Fetching: bindata-2.4.4.gem (100%)
Successfully installed bindata-2.4.4
Fetching: aes_key_wrap-1.0.1.gem (100%)
Successfully installed aes_key_wrap-1.0.1
Fetching: json-jwt-1.10.2.gem (100%)
Successfully installed json-jwt-1.10.2
Parsing documentation for bindata-2.4.4
Installing ri documentation for bindata-2.4.4
Parsing documentation for aes_key_wrap-1.0.1
Installing ri documentation for aes_key_wrap-1.0.1
Parsing documentation for json-jwt-1.10.2
Installing ri documentation for json-jwt-1.10.2
Done installing documentation for bindata, aes_key_wrap, json-jwt after 2 seconds
3 gems installed

Simple test file mytest.rb:

require 'json-jwt'
puts 'this worked!'

then run ruby mytest.rb

Leads to error:

/usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require': cannot load such file -- json-jwt (LoadError)
RubyGems Environment:
  - RUBYGEMS VERSION: 2.7.6.2
  - RUBY VERSION: 2.5.5 (2019-03-15 patchlevel 157) [arm-linux-gnueabihf]
  - INSTALLATION DIRECTORY: /var/lib/gems/2.5.0
  - USER INSTALLATION DIRECTORY: /home/pi/.gem/ruby/2.5.0
  - RUBY EXECUTABLE: /usr/bin/ruby2.5
  - EXECUTABLE DIRECTORY: /usr/local/bin
  - SPEC CACHE DIRECTORY: /home/pi/.gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /etc
  - RUBYGEMS PLATFORMS:
    - ruby
    - arm-linux
  - GEM PATHS:
     - /var/lib/gems/2.5.0
     - /home/pi/.gem/ruby/2.5.0
     - /usr/lib/arm-linux-gnueabihf/rubygems-integration/2.5.0
     - /usr/share/rubygems-integration/2.5.0
     - /usr/share/rubygems-integration/all
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /usr/local/sbin
     - /usr/local/bin
     - /usr/sbin
     - /usr/bin
     - /sbin
     - /bin
     - /usr/local/games
     - /usr/games

Decode jwt without verifying

Ran into some API limits against a well known jwks endpoint,

Wondering if there is a way to use the library in it's current format and decode a token for the public claims without validating it. You can do this in ruby-jwt but I mich prefer this project

Current

jwks_data = JSON.parse(Faraday.get('https://identity.my-domain.com/.well-known/openid-configuration/jwks').body)
jwk_set = JSON::JWK::Set.new(jwks_data)
JSON::JWT.decode(tkn, jwk_set)

Proposed || does this functionality exist?

JSON::JWT.decode(tkn, validate: false)

[SECURITY] Algorithm Confusion Through kid Header

Your JWS implementation correctly rejects invalid algorithms.

elsif algorithms.blank? || Array(algorithms).include?(alg&.to_sym)

However, when a kid header is present, it fetches the key after this algorithm check.

json-jwt/lib/json/jws.rb

Lines 124 to 140 in a2b4c15

public_key_or_secret = with_jwk_support public_key_or_secret
case
when hmac?
secure_compare sign(signature_base_string, public_key_or_secret), signature
when rsa?
public_key = public_key_or_secret
public_key.verify digest, signature, signature_base_string
when rsa_pss?
public_key = public_key_or_secret
public_key.verify_pss digest, signature, signature_base_string, salt_length: :digest, mgf1_hash: digest
when ecdsa?
public_key = public_key_or_secret
verify_ecdsa_group! public_key
public_key.verify digest, raw_to_asn1(signature, public_key), signature_base_string
else
raise UnexpectedAlgorithm.new('Unknown Signature Algorithm')
end

def with_jwk_support(key)
case key
when JSON::JWK
key.to_key
when JSON::JWK::Set
key.detect do |jwk|
jwk[:kid] && jwk[:kid] == kid
end&.to_key or raise JWK::Set::KidNotFound
else
key
end
end

When JWKs are used, this algorithm check isn't congruently applied to the keys.

json-jwt/lib/json/jwk.rb

Lines 40 to 51 in a2b4c15

def to_key
case
when rsa?
to_rsa_key
when ec?
to_ec_key
when oct?
self[:k]
else
raise UnknownAlgorithm.new('Unknown Key Type')
end
end

Therefore, if someone initializes a JWK or JWK::Set with different algorithm types, it's possible to swap the alg header and get the wrong key for a given algorithm. In extreme cases, this can lead to a cryptographic integrity bypass (reminiscent of the HS256/RS256 issue from years ago).

This is identical to the problem in firebase/php-jwt#351 https://seclists.org/fulldisclosure/2021/Aug/14

To fix this issue: Keys MUST be stored, in memory, as both the raw key bytes and the specific algorithm the key is expected to be used with. After fetching a key, this algorithm MUST be validated against the algorithms array.

Note: This particular sharp edge isn't covered by the JWT Best Practices RFC.

Encrypt then Sign

Sign then encrypt enforces the server to decrypt the token before the validation of the sender can be verified. From my point of view this seems to be inefficient and not best practice.
Am I right, that the gem just supports the method sign then encrypt and not encrypt then sign?

Minimum ruby version?

I was curious to know what minimum version of ruby you were targeting with this library. I noticed your use of url_safe_base64 might be related to attempting to support older rubies?

The reason I ask is that there's at least one corner case in decoding Base64-encoded data that is incorrectly handled in url_safe_base64 that I'd either like to address or remove the dependency on the library.

jti claim in JWT header

Hi,

Do you support setting the jti claim in the JWT header? It seems like it should be a registered header key but isn't.

Thanks,

John

Token to string doesn't match the original compact token

Good evening,
we are using this gem to decode and verify OpenID Connect tokens.
Since we are using it to authenticate different services with each other, after verification we sometimes need to send the token back to the auth service. That's how we discovered that doing token.to_s is not idempotent. In particular:

@token = 'myjwttoken'

JSON::JWT.decode(@token, 'secret').to_s == @token # => false

Any idea why, and how can we fix this problem?

/cc @emaserafini

1.6.2 broke backwards compatibility, no longer sets algorithm when signing JWT

In 1.6.2, JSON::JWT.sign started calling JWS.new self.dup instead of JSW.new self.

This has caused acme-client, who depends on json-jwt, to start failing with errors "algorithm 'none' in JWS header not acceptable": unixcharles/acme-client#74

Editing lib/json/jwt.rb and removing .dup makes these errors go away. The errors are not present when running with json-jwt 1.5.2 or 1.6.1, so it seems like something has broken backwards compatibility in the patch version 1.6.2.

Algorithm autodetection does not consider JWK

Ran into this while upgrading an app from 1.8.3 to 1.9.3: JSON::JWS::UnexpectedAlgorithm: Signature algorithm auto-detection failed in the following test helper:

def test_token(claims)
  jwt = JSON::JWT.new(claims).sign(jwk)
end

def jwk
  @jwk ||= JSON::JWK.new(private_key)
end

def private_key
  @private_key ||= OpenSSL::PKey::RSA.new(2048)
end

After digging in the commits, I noticed 4708f7d meant previously it was autodetected as :RS256.

verify signature JWT

I have a JWT

"eyJhbGciOiJSUzI1Ni..."

I can get the public key as a Ruby hash:

{"use"=>"sig",
 "kty"=>"RSA",
 "kid"=>"public",
 "n"=>
  "usTrcR3PIAKm37Q1...",
 "e"=>"AQAB"}
JSON::JWT.decode jwt, :skip_verification
=> {"aud"=>"e0172bf8-9d09-4ed8-b8ac-b1d07b43ae77",
 "exp"=>1487993654,
 "jti"=>"131bc753-bdd9-40e3-901c-a80a61240740",
 "redir"=> "https://test.....org/oauth2/auth?client_id=e01....",
 "scp"=>["hydra", "offline", "openid"]
}

BUT

jwk2 = JSON::JWK.new jwk
JSON::JWT.decode jwt , jwk2
ArgumentError: wrong number of arguments (given 0, expected 1)
from /home/ernst/.rvm/gems/[email protected]_students/gems/keystores-0.2.0/lib/keystores/jks/pkcs8_key.rb:63:in `block in <class:RSA>'

Header params overwritten when signing

Hello,

I've been using this gem in combination with your OpenIDConnect gem. When converting an IdToken to JWT, I've been setting some header parameters like so:

claims = { ... }
id_token = OpenIDConnect::ResponseObject::IdToken.new(claims)
signing_key = '...'

jwt = id_token.to_jwt(signing_key) do |token|
  token.x5u = 'http://www.example.com/'
end

However, when upgrading the JSON::JWT gem from version 1.5 to 1.6, I have unit tests failing due to these header parameters being lost.

This is apparently caused by this change: calling dup here doesn't copy over the header data to the new object.

License missing from gemspec

RubyGems.org doesn't report a license for your gem. This is because it is not specified in the gemspec of your last release.

via e.g.

spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']

Including a license in your gemspec is an easy way for rubygems.org and other tools to check how your gem is licensed. As you can imagine, scanning your repository for a LICENSE file or parsing the README, and then attempting to identify the license or licenses is much more difficult and more error prone. So, even for projects that already specify a license, including a license in your gemspec is a good practice. See, for example, how rubygems.org uses the gemspec to display the rails gem license.

There is even a License Finder gem to help companies/individuals ensure all gems they use meet their licensing needs. This tool depends on license information being available in the gemspec. This is an important enough issue that even Bundler now generates gems with a default 'MIT' license.

I hope you'll consider specifying a license in your gemspec. If not, please just close the issue with a nice message. In either case, I'll follow up. Thanks for your time!

Appendix:

If you need help choosing a license (sorry, I haven't checked your readme or looked for a license file), GitHub has created a license picker tool. Code without a license specified defaults to 'All rights reserved'-- denying others all rights to use of the code.
Here's a list of the license names I've found and their frequencies

p.s. In case you're wondering how I found you and why I made this issue, it's because I'm collecting stats on gems (I was originally looking for download data) and decided to collect license metadata,too, and make issues for gemspecs not specifying a license as a public service :). See the previous link or my blog post about this project for more information.

Any objection to me adding a :skip_verification example to your wiki docs?

I propose adding this section. It appears I have permission to edit that wiki page but I just want to clear it with you @nov. My use case is when I get a key verification failure I'd still like decode token so I can see what went wrong...

Decode without verifying (not recommended, use for debugging only)

id_token = JSON::JWT.decode id_token_string, :skip_verification
puts id_token.to_json

test failures with ruby3.0

Hi,

when trying to rebuild the Debian package associated to this gem with ruby3.0, we get the following failures:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=996303

I can reproduce these issues, with the HEAD of the repo. Everything is fine with ruby2.7, but the following 8 tests fail with ruby3.0.

Failures:

  1) JSON::JWS#to_json when syntax option given when general should return General JWS JSON Serialization
     Failure/Error:
       signed.to_json(syntax: :general).should == {
         payload: Base64.urlsafe_encode64(claims.to_json, padding: false),
         signatures: [{
           protected: Base64.urlsafe_encode64(signed.header.to_json, padding: false),
           signature: Base64.urlsafe_encode64(signed.signature, padding: false)
         }]
       }.to_json
     
       expected: "{\"payload\":\"eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlf...GUopIoxoqe4XjoBpzE5UvhrVl5LYbdjbyJhu5ZIA8GLsgwtUFh3dfdIechORoR3k5NSFSv8157bAEa8t4iwgWD2MSNSQnw\"}]}"
            got: "{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}" (using ==)
     # ./spec/json/jws_spec.rb:383:in `block (5 levels) in <top (required)>'

  2) JSON::JWS#to_json when syntax option given when general with blank payload should return General JWS JSON Serialization
     Failure/Error:
       signed_blank.to_json(syntax: :general).should == {
         payload: '',
         signatures: [{
           protected: Base64.urlsafe_encode64(signed_blank.header.to_json, padding: false),
           signature: Base64.urlsafe_encode64(signed_blank.signature, padding: false)
         }]
       }.to_json
     
       expected: "{\"payload\":\"\",\"signatures\":[{\"protected\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9\",\"signatur...s43GtT5bm-aJoMLct0nO1GBapQAiKUknTsw24IfOkX4vJNQzIWVSzx3zOxXjcVHlH92af6NknIlPCfRparLC9YEK2NkJYg\"}]}"
            got: "{}" (using ==)
     # ./spec/json/jws_spec.rb:393:in `block (6 levels) in <top (required)>'

  3) JSON::JWS#to_json when syntax option given when general when not signed yet should not fail
     Failure/Error:
       jws.to_json(syntax: :general).should == {
         payload: Base64.urlsafe_encode64(claims.to_json, padding: false),
         signatures: [{
           protected: Base64.urlsafe_encode64(jws.header.to_json, padding: false),
           signature: Base64.urlsafe_encode64('', padding: false)
         }]
       }.to_json
     
       expected: "{\"payload\":\"eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\",\"signatures\":[{\"protected\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9\",\"signature\":\"\"}]}"
            got: "{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}" (using ==)
     # ./spec/json/jws_spec.rb:405:in `block (6 levels) in <top (required)>'

  4) JSON::JWS#to_json when syntax option given when general when not signed yet with blank payload should not fail
     Failure/Error:
       jws_blank.to_json(syntax: :general).should == {
         payload: '',
         signatures: [{
           protected: Base64.urlsafe_encode64(jws_blank.header.to_json, padding: false),
           signature: Base64.urlsafe_encode64('', padding: false)
         }]
       }.to_json
     
       expected: "{\"payload\":\"\",\"signatures\":[{\"protected\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9\",\"signature\":\"\"}]}"
            got: "{}" (using ==)
     # ./spec/json/jws_spec.rb:415:in `block (7 levels) in <top (required)>'

  5) JSON::JWS#to_json when syntax option given when flattened should return Flattened JWS JSON Serialization
     Failure/Error:
       signed.to_json(syntax: :flattened).should == {
         protected: Base64.urlsafe_encode64(signed.header.to_json, padding: false),
         payload: Base64.urlsafe_encode64(claims.to_json, padding: false),
         signature: Base64.urlsafe_encode64(signed.signature, padding: false)
       }.to_json
     
       expected: "{\"protected\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9\",\"payload\":\"eyJpc3MiOiJqb2UiLCJleHAiOjEzMD...LVGUopIoxoqe4XjoBpzE5UvhrVl5LYbdjbyJhu5ZIA8GLsgwtUFh3dfdIechORoR3k5NSFSv8157bAEa8t4iwgWD2MSNSQnw\"}"
            got: "{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}" (using ==)
     # ./spec/json/jws_spec.rb:429:in `block (5 levels) in <top (required)>'

  6) JSON::JWS#to_json when syntax option given when flattened with blank payload should return Flattened JWS JSON Serialization
     Failure/Error:
       signed_blank.to_json(syntax: :flattened).should == {
         protected: Base64.urlsafe_encode64(signed_blank.header.to_json, padding: false),
         payload: '',
         signature: Base64.urlsafe_encode64(signed_blank.signature, padding: false)
       }.to_json
     
       expected: "{\"protected\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9\",\"payload\":\"\",\"signature\":\"WthQjouPVbE...Mns43GtT5bm-aJoMLct0nO1GBapQAiKUknTsw24IfOkX4vJNQzIWVSzx3zOxXjcVHlH92af6NknIlPCfRparLC9YEK2NkJYg\"}"
            got: "{}" (using ==)
     # ./spec/json/jws_spec.rb:437:in `block (6 levels) in <top (required)>'

  7) JSON::JWS#to_json when syntax option given when flattened when not signed yet should not fail
     Failure/Error:
       jws.to_json(syntax: :flattened).should == {
         protected: Base64.urlsafe_encode64(jws.header.to_json, padding: false),
         payload: Base64.urlsafe_encode64(claims.to_json, padding: false),
         signature: Base64.urlsafe_encode64('', padding: false)
       }.to_json
     
       expected: "{\"protected\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9\",\"payload\":\"eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\",\"signature\":\"\"}"
            got: "{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}" (using ==)
     # ./spec/json/jws_spec.rb:447:in `block (6 levels) in <top (required)>'

  8) JSON::JWS#to_json when syntax option given when flattened when not signed yet with blank payload should not fail
     Failure/Error:
       jws_blank.to_json(syntax: :flattened).should == {
         protected: Base64.urlsafe_encode64(jws_blank.header.to_json, padding: false),
         payload: '',
         signature: Base64.urlsafe_encode64('', padding: false)
       }.to_json
     
       expected: "{\"protected\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9\",\"payload\":\"\",\"signature\":\"\"}"
            got: "{}" (using ==)
     # ./spec/json/jws_spec.rb:455:in `block (7 levels) in <top (required)>'

Finished in 0.56325 seconds (files took 0.55478 seconds to load)
380 examples, 8 failures, 6 pending

Thanks!

Thread safety?

For example, given a $jwk which is a JSON::JWK::Set, would there be race condition when multiple threads do JSON::JWT.decode(token, $jwk) simultaneously?

OpenSSL::PKey interface has changed in Ruby 2.4

The attributes e, n, d, etc are no longer directly accessible. Those attributes are now set through setter functions:
https://ruby-doc.org/stdlib-2.4.1/libdoc/openssl/rdoc/OpenSSL/PKey/RSA.html#method-i-set_key
https://ruby-doc.org/stdlib-2.4.1/libdoc/openssl/rdoc/OpenSSL/PKey/RSA.html#method-i-set_factors
https://ruby-doc.org/stdlib-2.4.1/libdoc/openssl/rdoc/OpenSSL/PKey/RSA.html#method-i-set_crt_params

I had a pull request #44 to update JWK#to_rsa_key but it breaks for versions of Ruby < 2.4. The simplest solution is to check the OpenSSL version before attempting to set the key attributes. If you don't have any objections or a better solution, I'm happy to submit a PR with the change.

kid is being considered required

I don't know much ruby, but as far as I could understand, this code is considering the kid as REQUIRED whereas the RFC states that Use of this Header Parameter is OPTIONAL.

The JWT in question gets validated successfully at jwt.io.

I just want to let you know this is happening. I'll just use the kid anyways since it seems to be a good practice.

A128CBC-HS256

Hi,

in the draft in http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-14 i can read this:

Replaced "A128CBC+HS256" and "A256CBC+HS512" with "A128CBC-HS256" and "A256CBC-HS512". The new algorithms perform the same cryptographic computations as [I-D.mcgrew-aead-aes-cbc-hmac-sha2], but with the Initialization Vector and Authentication Tag values remaining separate from the Ciphertext value in the output representation. Also deleted the header parameters "epu"(encryption PartyUInfo) and "epv" (encryption PartyVInfo), since they are no longer used.

Will you update the gem to work properly with this change in the draft? If you know what changes should be made in JSON::JWE perhaps i'll be able to code them.

An example of the problem i have. Trying to decode with A128CBC+HS256 i have this error when calling JSON::JWE#decrypt! method:

OpenSSL::Cipher::CipherError Exception: wrong final block length

Thanks.

twistlock security scan shows that privatekeys are stored in the container

Private keys stored in image Found: /usr/local/bundle/gems/json-jwt-1.10.0/spec/fixtures/ecdsa/256/private_key.pem, /usr/local/bundle/gems/json-jwt-1.10.0/spec/fixtures/ecdsa/384/private_key.pem, /usr/local/bundle/gems/json-jwt-1.10.0/spec/fixtures/ecdsa/512/private_key.pem, /usr/local/bundle/gems/json-jwt-1.10.0/spec/fixtures/rsa/private_key.pem

Need to ignore the the spec files when packaging the gem.

NoMethodError: undefined method `group=' for #<String:0x007fc76c403dd8>

jwt = "eyJhbGciOiJFUzI1NiJ9.eyJub25jZSI6IjAwMTIwMTMtMDUtMTVUMjI6NTA6MjlaRGtTeG5ZIn0.ajC-scV2RLyiH9C2OFjZAz6MTHXsxuYXPB65eAfqraOkc8ipaxp6KiQbdmodk8ygnn1Imp5G5T0B8F9GfL6U0w"

public_key = "EQXDwFx0dcousKlUYWYfUzDnotvXvtdER3cIuCvTh31QGB4dUTszSgAUTg/4tIpsraycySiYFwlzLYJs35CumQ"

JSON::JWT.decode(jwt,public_key)

NoMethodError: undefined method group=' for #<String:0x007fc76c403dd8> from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/json-jwt-0.5.2/lib/json/jws.rb:94:inverify_ecdsa_group!'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/json-jwt-0.5.2/lib/json/jws.rb:78:in valid?' from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/json-jwt-0.5.2/lib/json/jws.rb:20:inverify'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/json-jwt-0.5.2/lib/json/jwt.rb:54:in verify' from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/json-jwt-0.5.2/lib/json/jwt.rb:93:indecode'
from (irb):9
from /usr/local/rvm/rubies/ruby-1.9.3-p392/bin/irb:16:in `

'

verify throwing an error in JSON::JWT.decode

In https://github.com/onli/sinatra-browserid/blob/88ae06ebf8248a277759f9917eb65249cf6711c2/lib/sinatra/browserid.rb#L35 I'm calling decode on string which is generated in https://github.com/callahad/authbackend/blob/e14f16899fc7a3dadf84651b897eac2eccc1d74d/server.rb#L381, by JWT.encode. If not skipping verification, this is leading to an error:

NoMethodError - undefined method `verify' for #<String:0x00000003e86478>:
    /home/onli/Dropbox-decrypted/ursprung.git/vendor/bundle/ruby/2.2.0/gems/json-jwt-1.5.2/lib/json/jws.rb:94:in `valid?'
    /home/onli/Dropbox-decrypted/ursprung.git/vendor/bundle/ruby/2.2.0/gems/json-jwt-1.5.2/lib/json/jws.rb:25:in `verify!'
    /home/onli/Dropbox-decrypted/ursprung.git/vendor/bundle/ruby/2.2.0/gems/json-jwt-1.5.2/lib/json/jws.rb:162:in `decode_compact_serialized'
    /home/onli/Dropbox-decrypted/ursprung.git/vendor/bundle/ruby/2.2.0/gems/json-jwt-1.5.2/lib/json/jwt.rb:77:in `decode_compact_serialized'
    /home/onli/Dropbox-decrypted/ursprung.git/vendor/bundle/ruby/2.2.0/gems/json-jwt-1.5.2/lib/json/jose.rb:39:in `decode'

I'm assuming I have to wrap the jwt-token-string in something. But this is not covered by the docu in https://github.com/nov/json-jwt/wiki/JWS#verifying, where that function is called with a normal string. Thus I assume this is a bug in docu or implementation.

What's the problem with activesupport v4

I saw your comment that you reject activesupport 4. Unfortunately that creates conflict in my app.

rubygems/specification.rb:1637:in `raise_if_conflicts': Unable to activate json-jwt-0.5.5, because activesupport-4.0.0 conflicts with activesupport (< 4) (Gem::LoadError)

Wondering?

Update Bindata Dependency Due To Security Issue

Please check the following links to get more info:

rubysec/ruby-advisory-db#476
rubysec/ruby-advisory-db#483
dmendel/bindata@d99f050
GHSA-hj56-84jw-67h6

---
gem: bindata
cve: 2021-32823
ghsa: hj56-84jw-67h6
url: https://github.com/rubysec/ruby-advisory-db/issues/476
date: 2021-05-18
title: Potential Denial-of-Service in bindata
description: |
  In bindata before version 2.4.10, there is a potential denial-of-service
  vulnerability. In affected versions, it is very slow for certain classes in BinData
  to be created. For example BinData::Bit100000, BinData::Bit100001, BinData::Bit100002,
  BinData::Bit<N>. In combination with `<user_input>.constantize` there is a potential
  for a CPU-based DoS. In version 2.4.10, bindata improved the creation time of Bits
  and Integers.
cvss_v3: 3.7

patched_versions:
- ">= 2.4.10"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.