Skip to content

Commit

Permalink
Bing back old apis and specs
Browse files Browse the repository at this point in the history
  • Loading branch information
anakinj committed Oct 1, 2024
1 parent 685a245 commit 3199688
Show file tree
Hide file tree
Showing 8 changed files with 569 additions and 1 deletion.
3 changes: 3 additions & 0 deletions lib/jwt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
require 'jwt/jwk'
require 'jwt/claims'

require 'jwt/claims_validator'
require 'jwt/verify'

# JSON Web Token implementation
#
# Should be up to date with the latest spec:
Expand Down
2 changes: 1 addition & 1 deletion lib/jwt/claims.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module Claims
class << self
def verify!(payload, options)
VERIFIERS.each do |key, verifier_builder|
next unless options[key]
next unless options[key] || options[key.to_s]

verifier_builder&.call(options)&.verify!(context: VerificationContext.new(payload: payload))
end
Expand Down
18 changes: 18 additions & 0 deletions lib/jwt/claims_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

require_relative 'error'

module JWT
class ClaimsValidator
def initialize(payload)
Deprecations.warning('The ::JWT::ClaimsValidator class is deprecated and will be removed in future version of ruby-jwt')
@payload = payload
end

def validate!
Claims::Numeric.verify!(payload: @payload)

true
end
end
end
5 changes: 5 additions & 0 deletions lib/jwt/jwa.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ def resolve(algorithm)

algorithm
end

def create(algorithm)
Deprecations.warning('The ::JWT::JWA.create method is deprecated and will be removed in future ruby-jwt versions')
resolve(algorithm)
end
end
end
end
118 changes: 118 additions & 0 deletions lib/jwt/verify.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# frozen_string_literal: true

require 'jwt/error'

module JWT
# JWT verify methods
class Verify
DEFAULTS = {
leeway: 0
}.freeze

class << self
%w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub verify_required_claims].each do |method_name|
define_method method_name do |payload, options|
new(payload, options).send(method_name)
end
end

def verify_claims(payload, options)
options.each do |key, val|
next unless key.to_s =~ /verify/

Verify.send(key, payload, options) if val
end
end
end

def initialize(payload, options)
Deprecations.warning('The ::JWT::Verify class is deprecated and will be removed in future version of ruby-jwt')
@payload = payload
@options = DEFAULTS.merge(options)
end

def verify_aud
return unless (options_aud = @options[:aud])

aud = @payload['aud']
raise JWT::InvalidAudError, "Invalid audience. Expected #{options_aud}, received #{aud || '<none>'}" if ([*aud] & [*options_aud]).empty?
end

def verify_expiration
return unless contains_key?(@payload, 'exp')
raise JWT::ExpiredSignature, 'Signature has expired' if @payload['exp'].to_i <= (Time.now.to_i - exp_leeway)
end

def verify_iat
return unless contains_key?(@payload, 'iat')

iat = @payload['iat']
raise JWT::InvalidIatError, 'Invalid iat' if !iat.is_a?(Numeric) || iat.to_f > Time.now.to_f
end

def verify_iss
return unless (options_iss = @options[:iss])

iss = @payload['iss']

options_iss = Array(options_iss).map { |item| item.is_a?(Symbol) ? item.to_s : item }

case iss
when *options_iss
nil
else
raise JWT::InvalidIssuerError, "Invalid issuer. Expected #{options_iss}, received #{iss || '<none>'}"
end
end

def verify_jti
options_verify_jti = @options[:verify_jti]
jti = @payload['jti']

if options_verify_jti.respond_to?(:call)
verified = options_verify_jti.arity == 2 ? options_verify_jti.call(jti, @payload) : options_verify_jti.call(jti)
raise JWT::InvalidJtiError, 'Invalid jti' unless verified
elsif jti.to_s.strip.empty?
raise JWT::InvalidJtiError, 'Missing jti'
end
end

def verify_not_before
return unless contains_key?(@payload, 'nbf')
raise JWT::ImmatureSignature, 'Signature nbf has not been reached' if @payload['nbf'].to_i > (Time.now.to_i + nbf_leeway)
end

def verify_sub
return unless (options_sub = @options[:sub])

sub = @payload['sub']
raise JWT::InvalidSubError, "Invalid subject. Expected #{options_sub}, received #{sub || '<none>'}" unless sub.to_s == options_sub.to_s
end

def verify_required_claims
return unless (options_required_claims = @options[:required_claims])

options_required_claims.each do |required_claim|
raise JWT::MissingRequiredClaim, "Missing required claim #{required_claim}" unless contains_key?(@payload, required_claim)
end
end

private

def global_leeway
@options[:leeway]
end

def exp_leeway
@options[:exp_leeway] || global_leeway
end

def nbf_leeway
@options[:nbf_leeway] || global_leeway
end

def contains_key?(payload, key)
payload.respond_to?(:key?) && payload.key?(key)
end
end
end
79 changes: 79 additions & 0 deletions spec/jwt/claims_validator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true

RSpec.describe JWT::ClaimsValidator do
let(:validator) { described_class.new(claims) }

describe '#validate!' do
subject { validator.validate! }

shared_examples_for 'a NumericDate claim' do |claim|
context "when #{claim} payload is an integer" do
let(:claims) { { claim => 12_345 } }

it 'does not raise error' do
expect { subject }.not_to raise_error
end

context 'and key is a string' do
let(:claims) { { claim.to_s => 43.32 } }

it 'does not raise error' do
expect { subject }.not_to raise_error
end
end
end

context "when #{claim} payload is a float" do
let(:claims) { { claim => 43.32 } }

it 'does not raise error' do
expect { subject }.not_to raise_error
end
end

context "when #{claim} payload is a string" do
let(:claims) { { claim => '1' } }

it 'raises error' do
expect { subject }.to raise_error JWT::InvalidPayload
end

context 'and key is a string' do
let(:claims) { { claim.to_s => '1' } }

it 'raises error' do
expect { subject }.to raise_error JWT::InvalidPayload
end
end
end

context "when #{claim} payload is a Time object" do
let(:claims) { { claim => Time.now } }

it 'raises error' do
expect { subject }.to raise_error JWT::InvalidPayload
end
end

context "when #{claim} payload is a string" do
let(:claims) { { claim => '1' } }

it 'raises error' do
expect { subject }.to raise_error JWT::InvalidPayload
end
end
end

context 'exp claim' do
it_should_behave_like 'a NumericDate claim', :exp
end

context 'iat claim' do
it_should_behave_like 'a NumericDate claim', :iat
end

context 'nbf claim' do
it_should_behave_like 'a NumericDate claim', :nbf
end
end
end
9 changes: 9 additions & 0 deletions spec/jwt/jwa_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

RSpec.describe JWT::JWA do
describe '.create' do
it 'finds an algorithm' do
expect(described_class.create('HS256')).to be_a(JWT::JWA::Hmac)
end
end
end
Loading

0 comments on commit 3199688

Please sign in to comment.