1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe OmniAuth::Strategies::Jwt do
include Rack::Test::Methods
include DeviseHelpers
describe '#decoded' do
subject { described_class.new({}) }
let(:timestamp) { Time.now.to_i }
let(:jwt_config) { Devise.omniauth_configs[:jwt] }
let(:claims) do
{
id: 123,
name: "user_example",
email: "user@example.com",
iat: timestamp
}
end
let(:algorithm) { 'HS256' }
let(:secret) { jwt_config.strategy.secret }
let(:private_key) { secret }
let(:payload) { JWT.encode(claims, private_key, algorithm) }
before do
subject.options[:secret] = secret
subject.options[:algorithm] = algorithm
# We use Rack::Request instead of ActionDispatch::Request because
# Rack::Test::Methods enables testing of this module.
expect_next_instance_of(Rack::Request) do |rack_request|
expect(rack_request).to receive(:params).and_return('jwt' => payload)
end
end
ecdsa_named_curves = {
'ES256' => 'prime256v1',
'ES384' => 'secp384r1',
'ES512' => 'secp521r1'
}.freeze
{
OpenSSL::PKey::RSA => %w[RS256 RS384 RS512],
OpenSSL::PKey::EC => %w[ES256 ES384 ES512],
String => %w[HS256 HS384 HS512]
}.each do |private_key_class, algorithms|
algorithms.each do |algorithm|
context "when the #{algorithm} algorithm is used" do
let(:algorithm) { algorithm }
let(:secret) do
if private_key_class == OpenSSL::PKey::RSA
private_key_class.generate(2048)
.to_pem
elsif private_key_class == OpenSSL::PKey::EC
private_key_class.new(ecdsa_named_curves[algorithm])
.tap { |key| key.generate_key! }
.to_pem
else
private_key_class.new(jwt_config.strategy.secret)
end
end
let(:private_key) { private_key_class ? private_key_class.new(secret) : secret }
it 'decodes the user information' do
result = subject.decoded
expect(result).to eq(claims.stringify_keys)
end
end
end
end
context 'required claims is missing' do
let(:claims) do
{
id: 123,
email: "user@example.com",
iat: timestamp
}
end
it 'raises error' do
expect { subject.decoded }.to raise_error(OmniAuth::Strategies::Jwt::ClaimInvalid)
end
end
context 'when valid_within is specified but iat attribute is missing in response' do
let(:claims) do
{
id: 123,
name: "user_example",
email: "user@example.com"
}
end
before do
# Omniauth config values are always strings!
subject.options[:valid_within] = 2.days.to_s
end
it 'raises error' do
expect { subject.decoded }.to raise_error(OmniAuth::Strategies::Jwt::ClaimInvalid)
end
end
context 'when timestamp claim is too skewed from present' do
let(:claims) do
{
id: 123,
name: "user_example",
email: "user@example.com",
iat: timestamp - 10.minutes.to_i
}
end
before do
# Omniauth config values are always strings!
subject.options[:valid_within] = 2.seconds.to_s
end
it 'raises error' do
expect { subject.decoded }.to raise_error(OmniAuth::Strategies::Jwt::ClaimInvalid)
end
end
end
end
|