omniauth-mlh 4.1.0 → 4.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e92f4278cc436382318b94bdac74133f166b1b7f9382e0920d03917c781ad2b
4
- data.tar.gz: ced9efbd0c899c448bf511dca3250ce6741a73f76af4b5fc57d009824bad1e26
3
+ metadata.gz: 641588bd9aad3201d3be389098e1d2a4a53b5179cc3edaec47c70a0f3191ca81
4
+ data.tar.gz: 2289268a506cc1c641ef83aefe912996c041343530efe6010b17a49b261f8ea5
5
5
  SHA512:
6
- metadata.gz: 1fba79bb10779ad12ee4b83a3230980fcb7431a82c10aa63274fc0ebf12b5df47d3914f077fc84e05738f0f60bb3e36fb4968b53ba3b1d2fa71a4fa3d73f4968
7
- data.tar.gz: 6035b246c632882bc231356f6d9500b79276252de689bd0f8660adc1fe5ef6abecc83210c9b1bbe1c57d22b8849276c03e37265a6f53edd1b0cf5f85a1e43bc3
6
+ metadata.gz: d5c441f65324cccf80c23cd39ab2d043c3e5ea4f93d08a009aeb2f6e3af1213f1281307692ef162d71af99d42de16defbd0fadfe46422b955b8136be770d45b0
7
+ data.tar.gz: cdcab860ce4e891fa4a92fc8f448e3464031ba0b9ba3eb221756606ad66763c717265234085b7441267dbf449ba95228ac6ef64c65715c95d55e4e37d59e7e2b
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  /.bundle/
2
+ /vendor/bundle/
2
3
  /.yardoc
3
4
  /Gemfile.lock
4
5
  /_yardoc/
@@ -30,12 +30,17 @@ module OmniAuth
30
30
  option :name, :mlh
31
31
 
32
32
  option :client_options, {
33
- site: 'https://my.mlh.io',
34
- authorize_url: 'oauth/authorize',
35
- token_url: 'oauth/token',
33
+ site: 'https://www.mlh.com',
34
+ authorize_url: '/oauth/authorize',
35
+ token_url: 'https://api.mlh.com/v4/oauth/token',
36
+ api_site: 'https://api.mlh.com',
36
37
  auth_scheme: :request_body # Change from basic auth to request body
37
38
  }
38
39
 
40
+ option :pkce, true
41
+
42
+ option :persist_credentials, true
43
+
39
44
  # Support expandable fields through options
40
45
  option :expand_fields, []
41
46
 
@@ -65,7 +70,8 @@ module OmniAuth
65
70
 
66
71
  def data
67
72
  @data ||= fetch_and_process_data.compact
68
- rescue StandardError
73
+ rescue ::OAuth2::Error, JSON::ParserError => e
74
+ OmniAuth.logger.warn("OmniAuth MLH: failed to load user data (#{e.class})")
69
75
  {}
70
76
  end
71
77
 
@@ -79,8 +85,21 @@ module OmniAuth
79
85
  symbolize_nested_arrays(data)
80
86
  end
81
87
 
88
+ # Preserve the OmniAuth credential shape without exposing bearer material.
89
+ def credentials
90
+ return super if options.persist_credentials
91
+
92
+ OmniAuth::AuthHash.new(
93
+ token: '',
94
+ refresh_token: nil,
95
+ secret: '',
96
+ expires: false
97
+ )
98
+ end
99
+
82
100
  def build_api_url
83
- url = 'https://api.mlh.com/v4/users/me'
101
+ base = (options.dig(:client_options, :api_site) || 'https://api.mlh.com').to_s.chomp('/')
102
+ url = "#{base}/v4/users/me"
84
103
  expand_fields = options[:expand_fields] || []
85
104
  return url if expand_fields.empty?
86
105
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OmniAuth
4
4
  module MLH
5
- VERSION = '4.1.0'
5
+ VERSION = '4.2.0'
6
6
  end
7
7
  end
@@ -5,7 +5,7 @@ require 'spec_helper'
5
5
  RSpec.describe OmniAuth::MLH do
6
6
  it 'has a version number' do
7
7
  expect(OmniAuth::MLH::VERSION).not_to be_nil
8
- expect(OmniAuth::MLH::VERSION).to eq('4.1.0')
8
+ expect(OmniAuth::MLH::VERSION).to eq('4.2.0')
9
9
  end
10
10
 
11
11
  it 'loads the MLH strategy' do
@@ -12,12 +12,45 @@ RSpec.describe OmniAuth::Strategies::MLH do
12
12
  allow(strategy).to receive(:access_token).and_return(access_token)
13
13
  end
14
14
 
15
+ describe 'client options' do
16
+ it 'uses the current MLH OAuth authorize and token endpoints' do
17
+ expect(strategy.options.client_options.authorize_url).to eq('/oauth/authorize')
18
+ expect(strategy.options.client_options.token_url).to eq('https://api.mlh.com/v4/oauth/token')
19
+ end
20
+
21
+ context 'with only api_site overridden' do
22
+ let(:strategy) do
23
+ described_class.new(app, 'client_id', 'client_secret',
24
+ client_options: { api_site: 'https://api.mlh.test' })
25
+ end
26
+
27
+ let(:token_request) do
28
+ stub_request(:post, 'https://api.mlh.com/v4/oauth/token')
29
+ .with(body: hash_including('client_id' => 'client_id', 'client_secret' => 'client_secret',
30
+ 'code' => 'authorization-code', 'grant_type' => 'authorization_code'))
31
+ .to_return(body: { access_token: 'test-token', token_type: 'Bearer' }.to_json,
32
+ headers: { 'Content-Type' => 'application/json' })
33
+ end
34
+
35
+ it 'preserves the OAuth authorization endpoint' do
36
+ expect(strategy.client.authorize_url).to eq('https://www.mlh.com/oauth/authorize')
37
+ end
38
+
39
+ it 'exchanges a code at the default token endpoint with credentials in the request body' do
40
+ token_request
41
+ expect(strategy.client.auth_code.get_token('authorization-code').token).to eq('test-token')
42
+ expect(token_request).to have_been_requested
43
+ end
44
+ end
45
+ end
46
+
15
47
  shared_context 'with oauth response' do |response_data|
16
48
  let(:oauth_response) do
17
49
  instance_double(OAuth2::Response,
18
50
  body: response_data.to_json,
19
51
  parsed: response_data)
20
52
  end
53
+
21
54
  before do
22
55
  allow(access_token).to receive(:get)
23
56
  .with('https://api.mlh.com/v4/users/me')
@@ -26,6 +59,21 @@ RSpec.describe OmniAuth::Strategies::MLH do
26
59
  end
27
60
 
28
61
  describe '#data' do
62
+ [nil, false].each do |expand_fields|
63
+ context "with expand_fields set to #{expand_fields.inspect}" do
64
+ let(:strategy) do
65
+ described_class.new(app, 'client_id', 'client_secret', expand_fields: expand_fields)
66
+ end
67
+
68
+ include_context 'with oauth response', { 'id' => 'core-user-1' }
69
+
70
+ it 'fetches user data without expansion parameters' do
71
+ expect(strategy.data).to eq(id: 'core-user-1')
72
+ expect(access_token).to have_received(:get).with('https://api.mlh.com/v4/users/me')
73
+ end
74
+ end
75
+ end
76
+
29
77
  context 'with expandable fields' do
30
78
  let(:response) do
31
79
  instance_double(OAuth2::Response, body: {}.to_json, parsed: {})
@@ -74,6 +122,30 @@ RSpec.describe OmniAuth::Strategies::MLH do
74
122
  end
75
123
  end
76
124
 
125
+ context 'with a custom api_site client option' do
126
+ let(:custom_strategy) do
127
+ described_class.new(app, 'client_id', 'client_secret',
128
+ client_options: { api_site: 'https://api.mlh.test' })
129
+ end
130
+
131
+ let(:response) do
132
+ instance_double(OAuth2::Response, body: { 'id' => 'core-user-1' }.to_json)
133
+ end
134
+
135
+ before do
136
+ allow(custom_strategy).to receive(:access_token).and_return(access_token)
137
+ allow(access_token).to receive(:get)
138
+ .with('https://api.mlh.test/v4/users/me')
139
+ .and_return(response)
140
+ end
141
+
142
+ it 'fetches user data from the configured API base' do
143
+ custom_strategy.data
144
+
145
+ expect(access_token).to have_received(:get).with('https://api.mlh.test/v4/users/me')
146
+ end
147
+ end
148
+
77
149
  context 'with v4 API complex data structures' do
78
150
  include_context 'with oauth response', {
79
151
  'id' => 'test-id',
@@ -142,13 +214,68 @@ RSpec.describe OmniAuth::Strategies::MLH do
142
214
  end
143
215
  end
144
216
 
145
- context 'with API error' do
146
- it 'returns empty hash on error' do
147
- allow(access_token).to receive(:get).and_raise(StandardError)
217
+ context 'with OAuth2::Error' do
218
+ let(:error_response) do
219
+ instance_double(OAuth2::Response,
220
+ status: 500,
221
+ headers: {},
222
+ body: '{"error": "server_error"}')
223
+ end
224
+
225
+ before do
226
+ allow(access_token).to receive(:get).and_raise(OAuth2::Error.new(error_response))
227
+ end
148
228
 
229
+ it 'returns empty payload for OAuth2 errors' do
149
230
  expect(strategy.data).to eq({})
150
231
  end
151
232
  end
233
+
234
+ context 'with malformed JSON' do
235
+ before do
236
+ allow(access_token).to receive(:get)
237
+ .and_return(instance_double(OAuth2::Response, body: '<html>not json</html>'))
238
+ end
239
+
240
+ it 'returns empty payload for JSON parse failures' do
241
+ expect(strategy.data).to eq({})
242
+ end
243
+ end
244
+
245
+ context 'with unexpected error' do
246
+ let(:unexpected_error_class) { Class.new(StandardError) }
247
+
248
+ before do
249
+ allow(access_token).to receive(:get).and_raise(unexpected_error_class, 'boom')
250
+ end
251
+
252
+ it 'propagates unexpected errors' do
253
+ expect { strategy.data }.to raise_error(unexpected_error_class)
254
+ end
255
+ end
256
+ end
257
+
258
+ describe '#auth_hash' do
259
+ let(:strategy) do
260
+ described_class.new(app, 'client_id', 'client_secret', persist_credentials: false)
261
+ end
262
+
263
+ let(:empty_credentials) do
264
+ {
265
+ 'token' => '',
266
+ 'refresh_token' => nil,
267
+ 'secret' => '',
268
+ 'expires' => false
269
+ }
270
+ end
271
+
272
+ before do
273
+ allow(strategy).to receive(:data).and_return(id: 'core-user-1')
274
+ end
275
+
276
+ it 'omits bearer credentials when persistence is disabled' do
277
+ expect(strategy.auth_hash['credentials']).to eq(empty_credentials)
278
+ end
152
279
  end
153
280
 
154
281
  describe '#uid' do
@@ -193,4 +320,25 @@ RSpec.describe OmniAuth::Strategies::MLH do
193
320
  expect(strategy.info[:roles]).to eq(['hacker'])
194
321
  end
195
322
  end
323
+
324
+ describe 'PKCE authorization' do
325
+ before { OmniAuth.config.test_mode = true }
326
+
327
+ after { OmniAuth.config.test_mode = false }
328
+
329
+ it 'uses S256 by default and sends the verifier only in token params' do
330
+ params = strategy.authorize_params
331
+
332
+ expect(params).to include(code_challenge: be_present, code_challenge_method: 'S256')
333
+ expect(params).not_to have_key(:code_verifier)
334
+ expect(strategy.token_params[:code_verifier]).to eq(strategy.options.pkce_verifier).and be_present
335
+ end
336
+
337
+ it 'can be disabled via the pkce option' do
338
+ disabled_strategy = described_class.new(app, 'client_id', 'client_secret', pkce: false)
339
+
340
+ expect(disabled_strategy.authorize_params).not_to include(:code_challenge, :code_challenge_method)
341
+ expect(disabled_strategy.token_params).not_to have_key(:code_verifier)
342
+ end
343
+ end
196
344
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-mlh
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Major League Hacking (MLH)
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-19 00:00:00.000000000 Z
11
+ date: 2026-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oauth2
@@ -194,7 +194,7 @@ homepage: http://github.com/mlh/omniauth-mlh
194
194
  licenses:
195
195
  - MIT
196
196
  metadata: {}
197
- post_install_message:
197
+ post_install_message:
198
198
  rdoc_options: []
199
199
  require_paths:
200
200
  - lib
@@ -210,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
210
210
  version: '0'
211
211
  requirements: []
212
212
  rubygems_version: 3.4.19
213
- signing_key:
213
+ signing_key:
214
214
  specification_version: 4
215
215
  summary: Official OmniAuth strategy for MyMLH.
216
216
  test_files: []