Skip to content

Commit

Permalink
Make the RbNaCl dependent tests optional
Browse files Browse the repository at this point in the history
  • Loading branch information
anakinj committed Oct 25, 2020
1 parent 72b003a commit f52b3a1
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 71 deletions.
6 changes: 5 additions & 1 deletion .travis.yml
@@ -1,3 +1,6 @@
sudo: required
cache: bundler
dist: trusty
language: ruby
rvm:
- 2.3
Expand All @@ -9,7 +12,8 @@ rvm:
- truffleruby-head
gemfile:
- gemfiles/standalone.gemfile
- gemfiles/openssl_2.1.gemfile
- gemfiles/openssl.gemfile
- gemfiles/rbnacl.gemfile
script:
- bundle exec rspec
- bundle exec codeclimate-test-reporter
Expand Down
10 changes: 10 additions & 0 deletions Appraisals
@@ -0,0 +1,10 @@
appraise 'standalone' do
end

appraise 'openssl' do
gem 'openssl', '~> 2.1'
end

appraise 'rbnacl' do
gem 'rbnacl'
end
7 changes: 7 additions & 0 deletions gemfiles/openssl.gemfile
@@ -0,0 +1,7 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "openssl", "~> 2.1"

gemspec path: "../"
Empty file removed gemfiles/openssl_2.1.gemfile
Empty file.
7 changes: 7 additions & 0 deletions gemfiles/rbnacl.gemfile
@@ -0,0 +1,7 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rbnacl"

gemspec path: "../"
1 change: 1 addition & 0 deletions ruby-jwt.gemspec
Expand Up @@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = %w[lib]

spec.add_development_dependency 'appraisal'
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'rspec'
Expand Down
2 changes: 1 addition & 1 deletion spec/integration/readme_examples_spec.rb
Expand Up @@ -79,7 +79,7 @@
{ 'data' => 'test' },
{ 'alg' => 'PS256' }
]
end
end if OpenSSL::VERSION >= '2.1'
end

context 'claims' do
Expand Down
162 changes: 93 additions & 69 deletions spec/jwt_spec.rb
Expand Up @@ -7,7 +7,7 @@
let(:payload) { { 'user_id' => 'some@user.tld' } }

let :data do
{
data = {
:secret => 'My$ecretK3y',
:rsa_private => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-private.pem'))),
:rsa_public => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-public.pem'))),
Expand All @@ -19,8 +19,6 @@
'ES384_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-public.pem'))),
'ES512_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-private.pem'))),
'ES512_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-public.pem'))),
'ED25519_private' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF'),
'ED25519_public' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF').verify_key,
'NONE' => 'eyJhbGciOiJub25lIn0.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.',
'HS256' => 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.kWOVtIOpWcG7JnyJG0qOkTDbOy636XrrQhMm_8JrRQ8',
'HS512256' => 'eyJhbGciOiJIUzUxMjI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Ds_4ibvf7z4QOBoKntEjDfthy3WJ-3rKMspTEcHE2bA',
Expand All @@ -36,6 +34,14 @@
'PS384' => '',
'PS512' => ''
}

if defined?(RbNaCl)
data.merge!(
'ED25519_private' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF'),
'ED25519_public' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF').verify_key,
)
end
data
end

after(:each) do
Expand Down Expand Up @@ -99,19 +105,22 @@
expect(validator).to receive(:validate!) { true }

payload = {}
JWT.encode payload, "secret", JWT::Algos::Hmac::SUPPORTED.sample
JWT.encode payload, "secret", 'HS256'
end

it 'does not validate the payload if it is not present' do
validator = double()
expect(JWT::ClaimsValidator).not_to receive(:new) { validator }

payload = nil
JWT.encode payload, "secret", JWT::Algos::Hmac::SUPPORTED.sample
JWT.encode payload, "secret", 'HS256'
end
end

%w[HS256 HS512256 HS384 HS512].each do |alg|
algorithms = %w[HS256 HS384 HS512]
algorithms << 'HS512256' if defined?(RbNaCl)

algorithms.each do |alg|
context "alg: #{alg}" do
it 'should generate a valid token' do
token = JWT.encode payload, data[:secret], alg
Expand Down Expand Up @@ -180,38 +189,40 @@
end
end

%w[ED25519].each do |alg|
context "alg: #{alg}" do
before(:each) do
data[alg] = JWT.encode payload, data["#{alg}_private"], alg
end
if defined?(RbNaCl)
%w[ED25519].each do |alg|
context "alg: #{alg}" do
before(:each) do
data[alg] = JWT.encode payload, data["#{alg}_private"], alg
end

let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) }
let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) }

it 'should generate a valid token' do
jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
it 'should generate a valid token' do
jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg

expect(header['alg']).to eq alg
expect(jwt_payload).to eq payload
end
expect(header['alg']).to eq alg
expect(jwt_payload).to eq payload
end

it 'should decode a valid token' do
jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
it 'should decode a valid token' do
jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg

expect(header['alg']).to eq alg
expect(jwt_payload).to eq payload
end
expect(header['alg']).to eq alg
expect(jwt_payload).to eq payload
end

it 'wrong key should raise JWT::DecodeError' do
expect do
JWT.decode data[alg], wrong_key
end.to raise_error JWT::DecodeError
end
it 'wrong key should raise JWT::DecodeError' do
expect do
JWT.decode data[alg], wrong_key
end.to raise_error JWT::DecodeError
end

it 'wrong key and verify = false should not raise JWT::DecodeError' do
expect do
JWT.decode data[alg], wrong_key, false
end.not_to raise_error
it 'wrong key and verify = false should not raise JWT::DecodeError' do
expect do
JWT.decode data[alg], wrong_key, false
end.not_to raise_error
end
end
end
end
Expand Down Expand Up @@ -252,51 +263,64 @@
end
end

%w[PS256 PS384 PS512].each do |alg|
context "alg: #{alg}" do
before(:each) do
data[alg] = JWT.encode payload, data[:rsa_private], alg
unless OpenSSL::VERSION >= '2.1'
%w[PS256 PS384 PS512].each do |alg|
context "alg: #{alg}" do
it 'raises error about OpenSSL version' do
expect { JWT.encode payload, data[:rsa_private], alg }.to raise_error(
JWT::RequiredDependencyError,
/You currently have OpenSSL .*. PS support requires >= 2.1/
)
end
end
end
else
%w[PS256 PS384 PS512].each do |alg|
context "alg: #{alg}" do
before(:each) do
data[alg] = JWT.encode payload, data[:rsa_private], alg
end

let(:wrong_key) { data[:wrong_rsa_public] }
let(:wrong_key) { data[:wrong_rsa_public] }

it 'should generate a valid token' do
token = data[alg]

header, body, signature = token.split('.')

expect(header).to eql(Base64.strict_encode64({ alg: alg }.to_json))
expect(body).to eql(Base64.strict_encode64(payload.to_json))

# Validate signature is made of up header and body of JWT
translated_alg = alg.gsub('PS', 'sha')
valid_signature = data[:rsa_public].verify_pss(
translated_alg,
JWT::Base64.url_decode(signature),
[header, body].join('.'),
salt_length: :auto,
mgf1_hash: translated_alg
)
expect(valid_signature).to be true
end
it 'should generate a valid token' do
token = data[alg]

it 'should decode a valid token' do
jwt_payload, header = JWT.decode data[alg], data[:rsa_public], true, algorithm: alg
header, body, signature = token.split('.')

expect(header['alg']).to eq alg
expect(jwt_payload).to eq payload
end
expect(header).to eql(Base64.strict_encode64({ alg: alg }.to_json))
expect(body).to eql(Base64.strict_encode64(payload.to_json))

it 'wrong key should raise JWT::DecodeError' do
expect do
JWT.decode data[alg], wrong_key
end.to raise_error JWT::DecodeError
end
# Validate signature is made of up header and body of JWT
translated_alg = alg.gsub('PS', 'sha')
valid_signature = data[:rsa_public].verify_pss(
translated_alg,
JWT::Base64.url_decode(signature),
[header, body].join('.'),
salt_length: :auto,
mgf1_hash: translated_alg
)
expect(valid_signature).to be true
end

it 'wrong key and verify = false should not raise JWT::DecodeError' do
expect do
JWT.decode data[alg], wrong_key, false
end.not_to raise_error
it 'should decode a valid token' do
jwt_payload, header = JWT.decode data[alg], data[:rsa_public], true, algorithm: alg

expect(header['alg']).to eq alg
expect(jwt_payload).to eq payload
end

it 'wrong key should raise JWT::DecodeError' do
expect do
JWT.decode data[alg], wrong_key
end.to raise_error JWT::DecodeError
end

it 'wrong key and verify = false should not raise JWT::DecodeError' do
expect do
JWT.decode data[alg], wrong_key, false
end.not_to raise_error
end
end
end
end
Expand Down

0 comments on commit f52b3a1

Please sign in to comment.