omniauth-jwt2 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +62 -0
  4. data/CITATION.cff +20 -0
  5. data/CODE_OF_CONDUCT.md +134 -0
  6. data/CONTRIBUTING.md +272 -0
  7. data/FUNDING.md +74 -0
  8. data/LICENSE.md +17 -0
  9. data/README.md +500 -58
  10. data/RUBOCOP.md +71 -0
  11. data/SECURITY.md +21 -0
  12. data/certs/pboling.pem +27 -0
  13. data/lib/omniauth/jwt/version.rb +6 -3
  14. data/lib/omniauth/jwt.rb +2 -1
  15. data/lib/omniauth/jwt2/version.rb +10 -0
  16. data/lib/omniauth/jwt2.rb +10 -0
  17. data/lib/omniauth/strategies/jwt.rb +31 -9
  18. data/sig/omniauth/jwt/version.rbs +8 -0
  19. data/sig/omniauth/jwt2/version.rbs +8 -0
  20. data.tar.gz.sig +0 -0
  21. metadata +263 -58
  22. metadata.gz.sig +0 -0
  23. data/.github/FUNDING.yml +0 -11
  24. data/.github/dependabot.yml +0 -2
  25. data/.github/workflows/ancient.yml +0 -53
  26. data/.github/workflows/ci.yml +0 -59
  27. data/.github/workflows/coverage.yml +0 -91
  28. data/.github/workflows/legacy.yml +0 -54
  29. data/.github/workflows/style.yml +0 -43
  30. data/.gitignore +0 -18
  31. data/.rspec +0 -2
  32. data/.rubocop.yml +0 -2
  33. data/.rubocop_gradual.lock +0 -39
  34. data/.simplecov +0 -2
  35. data/.tool-versions +0 -1
  36. data/Gemfile +0 -17
  37. data/Guardfile +0 -8
  38. data/LICENSE.txt +0 -23
  39. data/Rakefile +0 -23
  40. data/gemfiles/ancient.gemfile +0 -20
  41. data/gemfiles/contexts/coverage.gemfile +0 -2
  42. data/gemfiles/contexts/debug.gemfile +0 -6
  43. data/gemfiles/contexts/style.gemfile +0 -5
  44. data/gemfiles/contexts/testing.gemfile +0 -8
  45. data/gemfiles/coverage.gemfile +0 -20
  46. data/gemfiles/legacy.gemfile +0 -26
  47. data/gemfiles/style.gemfile +0 -20
  48. data/gemfiles/vanilla.gemfile +0 -20
  49. data/omniauth-jwt2.gemspec +0 -41
  50. data/spec/lib/omniauth/strategies/jwt_spec.rb +0 -213
  51. data/spec/spec_helper.rb +0 -64
  52. data/spec/support/hash.rb +0 -9
  53. data/spec/support/next_instance_of.rb +0 -43
@@ -1,213 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe OmniAuth::Strategies::JWT do
4
- let(:response_json) { JSON.parse(last_response.body) }
5
- let(:rand_secret) { SecureRandom.hex(10) }
6
- let(:args) { [rand_secret, {auth_url: "http://example.com/login"}] }
7
-
8
- let(:app) {
9
- the_args = args
10
- Rack::Builder.new do |b|
11
- b.use Rack::Session::Cookie, secret: SecureRandom.hex(32)
12
- b.use OmniAuth::Strategies::JWT, *the_args
13
- b.run lambda { |env|
14
- [200, {}, [(env["omniauth.auth"] || {}).to_json]]
15
- }
16
- end
17
- }
18
-
19
- context "request phase" do
20
- it "redirects to the configured login url" do
21
- # TODO: Figure out how to write this test without using the deprecated
22
- # and unsafe, "get" method for the request phase.
23
- get "/auth/jwt"
24
- expect(last_response.status).to eq(302)
25
- expect(last_response.headers["Location"]).to eq("http://example.com/login")
26
- end
27
- end
28
-
29
- context "callback phase" do
30
- it "decodes the response" do
31
- encoded = JWT.encode({name: "Bob", email: "steve@example.com"}, rand_secret)
32
- get "/auth/jwt/callback?jwt=" + encoded
33
- expect(response_json["info"]["email"]).to eq("steve@example.com")
34
- end
35
-
36
- it "does not work without required fields" do
37
- encoded = JWT.encode({name: "Steve"}, rand_secret)
38
- get "/auth/jwt/callback?jwt=" + encoded
39
- expect(last_response.status).to eq(302)
40
- end
41
-
42
- it "assigns the uid" do
43
- encoded = JWT.encode({name: "Steve", email: "dude@awesome.com"}, rand_secret)
44
- get "/auth/jwt/callback?jwt=" + encoded
45
- expect(response_json["uid"]).to eq("dude@awesome.com")
46
- end
47
-
48
- context "with a non-default encoding algorithm" do
49
- let(:args) { [rand_secret, {auth_url: "http://example.com/login", decode_options: {algorithms: ["HS512", "HS256"]}}] }
50
-
51
- it "decodes the response with an allowed algorithm" do
52
- encoded = JWT.encode({name: "Bob", email: "steve@example.com"}, rand_secret, "HS512")
53
- get "/auth/jwt/callback?jwt=" + encoded
54
- expect(JSON.parse(last_response.body)["info"]["email"]).to eq("steve@example.com")
55
-
56
- encoded = JWT.encode({name: "Bob", email: "steve@example.com"}, rand_secret, "HS256")
57
- get "/auth/jwt/callback?jwt=" + encoded
58
- expect(JSON.parse(last_response.body)["info"]["email"]).to eq("steve@example.com")
59
- end
60
-
61
- it "fails decoding the response with a different algorithm" do
62
- encoded = JWT.encode({name: "Bob", email: "steve@example.com"}, rand_secret, "HS384")
63
- get "/auth/jwt/callback?jwt=" + encoded
64
- expect(last_response.headers["Location"]).to include("/auth/failure")
65
- end
66
- end
67
-
68
- context "with a :valid_within option set" do
69
- let(:args) { [rand_secret, {auth_url: "http://example.com/login", valid_within: 300}] }
70
-
71
- it "works if the iat key is within the time window" do
72
- encoded = JWT.encode({name: "Ted", email: "ted@example.com", iat: Time.now.to_i}, rand_secret)
73
- get "/auth/jwt/callback?jwt=" + encoded
74
- expect(last_response.status).to eq(200)
75
- end
76
-
77
- it "does not work if the iat key is outside the time window" do
78
- encoded = JWT.encode({name: "Ted", email: "ted@example.com", iat: Time.now.to_i + 500}, rand_secret)
79
- get "/auth/jwt/callback?jwt=" + encoded
80
- expect(last_response.status).to eq(302)
81
- end
82
-
83
- it "does not work if the iat key is missing" do
84
- encoded = JWT.encode({name: "Ted", email: "ted@example.com"}, rand_secret)
85
- get "/auth/jwt/callback?jwt=" + encoded
86
- expect(last_response.status).to eq(302)
87
- end
88
- end
89
- end
90
-
91
- describe "#decoded" do
92
- subject { described_class.new({}) }
93
-
94
- let(:timestamp) { Time.now.to_i }
95
- let(:claims) do
96
- {
97
- id: 123,
98
- name: "user_example",
99
- email: "user@example.com",
100
- iat: timestamp,
101
- }
102
- end
103
-
104
- let(:algorithm) { "HS256" }
105
- let(:secret) { rand_secret }
106
- let(:private_key) { secret }
107
- let(:payload) { JWT.encode(claims, private_key, algorithm) }
108
-
109
- before do
110
- subject.options[:secret] = secret
111
- subject.options[:algorithm] = algorithm
112
-
113
- # We use Rack::Request instead of ActionDispatch::Request because
114
- # Rack::Test::Methods enables testing of this module.
115
- expect_next_instance_of(Rack::Request) do |rack_request|
116
- expect(rack_request).to receive(:params).and_return("jwt" => payload)
117
- end
118
- end
119
-
120
- ecdsa_named_curves = {
121
- "ES256" => "prime256v1",
122
- "ES384" => "secp384r1",
123
- "ES512" => "secp521r1",
124
- }.freeze
125
-
126
- algos = {
127
- OpenSSL::PKey::RSA => %w[RS256 RS384 RS512],
128
- String => %w[HS256 HS384 HS512],
129
- }
130
- algos.merge!(OpenSSL::PKey::EC => %w[ES256 ES384 ES512]) unless ["2.2.10", "2.3.8"].include?(RubyVersion.to_s)
131
- algos.each do |private_key_class, algorithms|
132
- algorithms.each do |algorithm|
133
- context "when the #{algorithm} algorithm is used" do
134
- let(:algorithm) { algorithm }
135
- let(:secret) do
136
- # rubocop:disable Style/CaseLikeIf
137
- if private_key_class == OpenSSL::PKey::RSA
138
- private_key_class.generate(2048)
139
- .to_pem
140
- elsif private_key_class == OpenSSL::PKey::EC
141
- private_key_class.generate(ecdsa_named_curves[algorithm])
142
- .to_pem
143
- else
144
- private_key_class.new(rand_secret)
145
- end
146
- # rubocop:enable Style/CaseLikeIf
147
- end
148
-
149
- let(:private_key) { private_key_class ? private_key_class.new(secret) : secret }
150
-
151
- it "decodes the user information" do
152
- result = subject.decoded
153
-
154
- expect(result).to eq(claims.stringify_keys)
155
- end
156
- end
157
- end
158
- end
159
-
160
- context "required claims is missing" do
161
- let(:claims) do
162
- {
163
- id: 123,
164
- email: "user@example.com",
165
- iat: timestamp,
166
- }
167
- end
168
-
169
- it "raises error" do
170
- expect { subject.decoded }.to raise_error(OmniAuth::Strategies::Jwt::ClaimInvalid)
171
- end
172
- end
173
-
174
- context "when valid_within is specified but iat attribute is missing in response" do
175
- let(:claims) do
176
- {
177
- id: 123,
178
- name: "user_example",
179
- email: "user@example.com",
180
- }
181
- end
182
-
183
- before do
184
- # Omniauth config values are always strings!
185
- subject.options[:valid_within] = (60 * 60 * 24 * 2).to_s # 2 days
186
- end
187
-
188
- it "raises error" do
189
- expect { subject.decoded }.to raise_error(OmniAuth::Strategies::Jwt::ClaimInvalid)
190
- end
191
- end
192
-
193
- context "when timestamp claim is too skewed from present" do
194
- let(:claims) do
195
- {
196
- id: 123,
197
- name: "user_example",
198
- email: "user@example.com",
199
- iat: timestamp - (60 * 60 * 10), # minus ten minutes
200
- }
201
- end
202
-
203
- before do
204
- # Omniauth config values are always strings!
205
- subject.options[:valid_within] = "2" # 2 seconds
206
- end
207
-
208
- it "raises error" do
209
- expect { subject.decoded }.to raise_error(OmniAuth::Strategies::Jwt::ClaimInvalid)
210
- end
211
- end
212
- end
213
- end
data/spec/spec_helper.rb DELETED
@@ -1,64 +0,0 @@
1
- # Std Lib
2
- require "securerandom"
3
-
4
- # 3rd party gems
5
- require "rspec/pending_for"
6
- begin
7
- require "rack/session"
8
- rescue LoadError
9
- nil # File won't exist in old rack for Ruby 2.2 & 2.3
10
- end
11
- require "rack/test"
12
- require "json"
13
- require "omniauth"
14
- begin
15
- require "openssl"
16
- require "openssl/signature_algorithm"
17
- require "ed25519"
18
- rescue LoadError
19
- nil # Gem doesn't exist for ancient Rubies 2.2 & 2.3
20
- end
21
-
22
- require "byebug" if ENV["DEBUG"] == "true"
23
- # This does not require "simplecov",
24
- # because that has a side-effect of running `.simplecov`
25
- begin
26
- require "kettle-soup-cover"
27
- rescue LoadError
28
- puts "Not analyzing test coverage"
29
- end
30
-
31
- require "support/hash"
32
- require "support/next_instance_of"
33
-
34
- OmniAuth.config.logger = Logger.new("/dev/null")
35
- require "omniauth/version"
36
- puts "OMNIAUTH VERSION: #{OmniAuth::VERSION}"
37
- if Gem::Version.new(OmniAuth::VERSION) > Gem::Version.new("2.0")
38
- OmniAuth.config.silence_get_warning = true
39
- OmniAuth.config.allowed_request_methods |= [:get, :post]
40
- end
41
- # This file was generated by the `rspec --init` command. Conventionally, all
42
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
43
- # Require this file using `require "spec_helper"` to ensure that it is only
44
- # loaded once.
45
- #
46
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
47
- RSpec.configure do |config|
48
- config.run_all_when_everything_filtered = true
49
- config.filter_run :focus
50
-
51
- include Rack::Test::Methods
52
- include NextInstanceOf
53
-
54
- # Run specs in random order to surface order dependencies. If you find an
55
- # order dependency and want to debug it, you can fix the order by providing
56
- # the seed, which is printed after each run.
57
- # --seed 1234
58
- config.order = "random"
59
- end
60
-
61
- # Last thing before loading this library, load simplecov:
62
- require "simplecov" if defined?(Kettle::Soup::Cover) && Kettle::Soup::Cover::DO_COV
63
-
64
- require "omniauth/jwt"
data/spec/support/hash.rb DELETED
@@ -1,9 +0,0 @@
1
- class Hash
2
- def self.stringify_keys(h)
3
- h.is_a?(Hash) ? h.collect { |k, v| [k.to_s, stringify_keys(v)] }.to_h : h
4
- end
5
-
6
- def stringify_keys
7
- self.class.stringify_keys(self)
8
- end
9
- end
@@ -1,43 +0,0 @@
1
- # From: https://github.com/gitlabhq/gitlabhq/blob/master/gems/gitlab-rspec/lib/gitlab/rspec/next_instance_of.rb#L4
2
- module NextInstanceOf
3
- def expect_next_instance_of(klass, *new_args, &blk)
4
- stub_new(expect(klass), nil, false, *new_args, &blk)
5
- end
6
-
7
- def expect_next_instances_of(klass, number, ordered = false, *new_args, &blk)
8
- stub_new(expect(klass), number, ordered, *new_args, &blk)
9
- end
10
-
11
- def allow_next_instance_of(klass, *new_args, &blk)
12
- stub_new(allow(klass), nil, false, *new_args, &blk)
13
- end
14
-
15
- def allow_next_instances_of(klass, number, ordered = false, *new_args, &blk)
16
- stub_new(allow(klass), number, ordered, *new_args, &blk)
17
- end
18
-
19
- private
20
-
21
- def stub_new(target, number, ordered = false, *new_args, &blk)
22
- receive_new = receive(:new)
23
- receive_new.ordered if ordered
24
- receive_new.with(*new_args) if !(new_args.empty? || new_args.blank?)
25
-
26
- if number.is_a?(Range)
27
- receive_new.at_least(number.begin).times if number.begin
28
- receive_new.at_most(number.end).times if number.end
29
- elsif number
30
- receive_new.exactly(number).times
31
- end
32
-
33
- target.to receive_new.and_wrap_original do |*original_args, **original_kwargs|
34
- method, *original_args = original_args
35
- begin
36
- method.call(*original_args, **original_kwargs).tap(&blk)
37
- rescue ArgumentError
38
- # Kludge for old ruby < 2.7
39
- method.call(*original_args).tap(&blk)
40
- end
41
- end
42
- end
43
- end