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 +4 -4
- data/.gitignore +1 -0
- data/lib/omniauth/strategies/mlh.rb +24 -5
- data/lib/omniauth-mlh/version.rb +1 -1
- data/spec/omni_auth/mlh_spec.rb +1 -1
- data/spec/omni_auth/strategies/mlh_spec.rb +151 -3
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 641588bd9aad3201d3be389098e1d2a4a53b5179cc3edaec47c70a0f3191ca81
|
|
4
|
+
data.tar.gz: 2289268a506cc1c641ef83aefe912996c041343530efe6010b17a49b261f8ea5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d5c441f65324cccf80c23cd39ab2d043c3e5ea4f93d08a009aeb2f6e3af1213f1281307692ef162d71af99d42de16defbd0fadfe46422b955b8136be770d45b0
|
|
7
|
+
data.tar.gz: cdcab860ce4e891fa4a92fc8f448e3464031ba0b9ba3eb221756606ad66763c717265234085b7441267dbf449ba95228ac6ef64c65715c95d55e4e37d59e7e2b
|
data/.gitignore
CHANGED
|
@@ -30,12 +30,17 @@ module OmniAuth
|
|
|
30
30
|
option :name, :mlh
|
|
31
31
|
|
|
32
32
|
option :client_options, {
|
|
33
|
-
site: 'https://
|
|
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
|
|
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
|
-
|
|
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
|
|
data/lib/omniauth-mlh/version.rb
CHANGED
data/spec/omni_auth/mlh_spec.rb
CHANGED
|
@@ -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.
|
|
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
|
|
146
|
-
|
|
147
|
-
|
|
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.
|
|
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:
|
|
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: []
|