Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore casing of algorithm #405

Merged
merged 13 commits into from Feb 9, 2021
25 changes: 13 additions & 12 deletions lib/jwt/decode.rb
Expand Up @@ -43,22 +43,23 @@ def verify_signature
end

def options_includes_algo_in_header?
allowed_algorithms.include? header['alg']
allowed_algorithms.include? header['alg'].upcase
end

def allowed_algorithms
# Order is very important - first check for string keys, next for symbols
if @options.key?('algorithm')
[@options['algorithm']]
elsif @options.key?(:algorithm)
[@options[:algorithm]]
elsif @options.key?('algorithms')
@options['algorithms'] || []
elsif @options.key?(:algorithms)
@options[:algorithms] || []
else
[]
end
algos = if @options.key?('algorithm')
@options['algorithm']
johnnyshields marked this conversation as resolved.
Show resolved Hide resolved
elsif @options.key?(:algorithm)
johnnyshields marked this conversation as resolved.
Show resolved Hide resolved
@options[:algorithm]
elsif @options.key?('algorithms')
johnnyshields marked this conversation as resolved.
Show resolved Hide resolved
@options['algorithms']
elsif @options.key?(:algorithms)
johnnyshields marked this conversation as resolved.
Show resolved Hide resolved
@options[:algorithms]
else
johnnyshields marked this conversation as resolved.
Show resolved Hide resolved
[]
end
johnnyshields marked this conversation as resolved.
Show resolved Hide resolved
Array(algos).map(&:upcase)
end

def find_key(&keyfinder)
Expand Down
4 changes: 3 additions & 1 deletion lib/jwt/signature.rb
Expand Up @@ -31,14 +31,16 @@ module Signature
ToVerify = Struct.new(:algorithm, :public_key, :signing_input, :signature)

def sign(algorithm, msg, key)
algorithm = algorithm.upcase
algo = ALGOS.find do |alg|
alg.const_get(:SUPPORTED).include? algorithm
end
algo.sign ToSign.new(algorithm, msg, key)
end

def verify(algorithm, key, signing_input, signature)
return true if algorithm == 'none'
algorithm = algorithm.upcase
return true if algorithm == 'NONE'

raise JWT::DecodeError, 'No verification key available' unless key

Expand Down
22 changes: 22 additions & 0 deletions spec/jwt_spec.rb
Expand Up @@ -510,4 +510,26 @@
end.not_to raise_error
end
end

context 'algorithm case insensitivity' do
let(:payload) { { 'a' => 1, 'b' => 'b' } }

it 'ignores algorithm casing during encode/decode' do
enc = JWT.encode(payload, '', 'hs256')
expect(JWT.decode(enc, '')).to eq([payload, { 'alg' => 'hs256'}])

enc = JWT.encode(payload, data[:rsa_private], 'ps384')
johnnyshields marked this conversation as resolved.
Show resolved Hide resolved
puts JWT.decode(enc, nil, false, algorithm: 'ps384').inspect
expect(JWT.decode(enc, data[:rsa_public], true, algorithm: 'PS384')).to eq([payload, { 'alg' => 'ps384'}])

enc = JWT.encode(payload, data[:rsa_private], 'RS512')
expect(JWT.decode(enc, data[:rsa_public], true, algorithm: 'rs512')).to eq([payload, { 'alg' => 'RS512'}])
end

it 'raises error for invalid algorithm' do
expect do
JWT.encode(payload, '', 'xyz')
end.to raise_error(NotImplementedError)
end
end
end