omniauth-identity 3.0.2 → 3.0.7
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/CHANGELOG.md +74 -0
- data/README.md +117 -42
- data/lib/omniauth-identity/version.rb +1 -1
- data/lib/omniauth/identity.rb +2 -0
- data/lib/omniauth/identity/model.rb +93 -30
- data/lib/omniauth/identity/models/active_record.rb +2 -2
- data/lib/omniauth/identity/models/couch_potato.rb +6 -0
- data/lib/omniauth/identity/models/mongoid.rb +1 -0
- data/lib/omniauth/identity/models/nobrainer.rb +31 -0
- data/lib/omniauth/identity/models/sequel.rb +48 -0
- data/lib/omniauth/identity/secure_password.rb +98 -37
- data/lib/omniauth/strategies/identity.rb +103 -32
- data/spec/omniauth/identity/model_spec.rb +19 -99
- data/spec/omniauth/identity/models/active_record_spec.rb +20 -11
- data/spec/omniauth/identity/models/sequel_spec.rb +38 -0
- data/spec/omniauth/strategies/identity_spec.rb +131 -16
- data/spec/spec_helper.rb +16 -4
- data/spec/support/shared_contexts/instance_with_instance_methods.rb +89 -0
- data/spec/support/shared_contexts/model_with_class_methods.rb +29 -0
- data/spec/support/shared_contexts/persistable_model.rb +24 -0
- metadata +29 -37
- data/spec/omniauth/identity/models/couch_potato_spec.rb +0 -19
- data/spec/omniauth/identity/models/mongoid_spec.rb +0 -26
@@ -1,123 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class ExampleModel
|
4
|
-
include OmniAuth::Identity::Model
|
5
|
-
end
|
6
|
-
|
7
3
|
RSpec.describe OmniAuth::Identity::Model do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
describe '.locate' do
|
12
|
-
it('is abstract') { expect { subject.locate('abc') }.to raise_error(NotImplementedError) }
|
4
|
+
before do
|
5
|
+
identity_test_klass = Class.new do
|
6
|
+
include OmniAuth::Identity::Model
|
13
7
|
end
|
8
|
+
stub_const('IdentityTestClass', identity_test_klass)
|
9
|
+
end
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
mocked_instance = double('ExampleModel', authenticate: 'abbadoo')
|
18
|
-
allow(subject).to receive(:locate).with('email' => 'example').and_return(mocked_instance)
|
19
|
-
expect(subject.authenticate({ 'email' => 'example' }, 'pass')).to eq('abbadoo')
|
20
|
-
end
|
11
|
+
describe 'Class Methods' do
|
12
|
+
subject(:model_klass) { IdentityTestClass }
|
21
13
|
|
22
|
-
|
23
|
-
mocked_instance = double('ExampleModel', authenticate: 'abbadoo')
|
24
|
-
allow(subject).to receive(:locate).with('email' => 'example',
|
25
|
-
'user_type' => 'admin').and_return(mocked_instance)
|
26
|
-
expect(subject.authenticate({ 'email' => 'example', 'user_type' => 'admin' }, 'pass')).to eq('abbadoo')
|
27
|
-
end
|
14
|
+
include_context 'model with class methods'
|
28
15
|
|
29
|
-
|
30
|
-
|
31
|
-
expect
|
16
|
+
describe '::locate' do
|
17
|
+
it('is abstract') do
|
18
|
+
expect { model_klass.locate('email' => 'example') }.to raise_error(NotImplementedError)
|
32
19
|
end
|
33
20
|
end
|
34
21
|
end
|
35
22
|
|
36
|
-
|
37
|
-
subject {
|
23
|
+
describe 'Instance Methods' do
|
24
|
+
subject(:instance) { IdentityTestClass.new }
|
38
25
|
|
39
|
-
|
40
|
-
it('is abstract') { expect { subject.authenticate('abc') }.to raise_error(NotImplementedError) }
|
41
|
-
end
|
26
|
+
include_context 'instance with instance methods'
|
42
27
|
|
43
|
-
describe '#
|
44
|
-
it '
|
45
|
-
allow(subject).to receive(:respond_to?).with(:id).and_return(true)
|
46
|
-
allow(subject).to receive(:id).and_return 'wakka-do'
|
47
|
-
expect(subject.uid).to eq('wakka-do')
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'stringifies it' do
|
51
|
-
allow(subject).to receive(:id).and_return 123
|
52
|
-
expect(subject.uid).to eq('123')
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'raises NotImplementedError if #id is not defined' do
|
56
|
-
allow(subject).to receive(:respond_to?).with(:id).and_return(false)
|
57
|
-
expect { subject.uid }.to raise_error(NotImplementedError)
|
58
|
-
end
|
28
|
+
describe '#authenticate' do
|
29
|
+
it('is abstract') { expect { instance.authenticate('my-password') }.to raise_error(NotImplementedError) }
|
59
30
|
end
|
60
31
|
|
61
32
|
describe '#auth_key' do
|
62
|
-
it 'defaults to #email' do
|
63
|
-
allow(subject).to receive(:respond_to?).with(:email).and_return(true)
|
64
|
-
allow(subject).to receive(:email).and_return('bob@bob.com')
|
65
|
-
expect(subject.auth_key).to eq('bob@bob.com')
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'uses the class .auth_key' do
|
69
|
-
subject.class.auth_key 'login'
|
70
|
-
allow(subject).to receive(:login).and_return 'bob'
|
71
|
-
expect(subject.auth_key).to eq('bob')
|
72
|
-
subject.class.auth_key nil
|
73
|
-
end
|
74
|
-
|
75
33
|
it 'raises a NotImplementedError if the auth_key method is not defined' do
|
76
|
-
expect {
|
34
|
+
expect { instance.auth_key }.to raise_error(NotImplementedError)
|
77
35
|
end
|
78
36
|
end
|
79
37
|
|
80
38
|
describe '#auth_key=' do
|
81
|
-
it '
|
82
|
-
|
83
|
-
expect(subject).to receive(:email=).with 'abc'
|
84
|
-
|
85
|
-
subject.auth_key = 'abc'
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'uses a custom .auth_key if one is provided' do
|
89
|
-
subject.class.auth_key 'login'
|
90
|
-
allow(subject).to receive(:respond_to?).with(:login=).and_return(true)
|
91
|
-
expect(subject).to receive(:login=).with('abc')
|
92
|
-
|
93
|
-
subject.auth_key = 'abc'
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'raises a NotImplementedError if the autH_key method is not defined' do
|
97
|
-
expect { subject.auth_key = 'broken' }.to raise_error(NotImplementedError)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
describe '#info' do
|
102
|
-
it 'includes attributes that are set' do
|
103
|
-
allow(subject).to receive(:name).and_return('Bob Bobson')
|
104
|
-
allow(subject).to receive(:nickname).and_return('bob')
|
105
|
-
|
106
|
-
expect(subject.info).to eq({
|
107
|
-
'name' => 'Bob Bobson',
|
108
|
-
'nickname' => 'bob'
|
109
|
-
})
|
110
|
-
end
|
111
|
-
|
112
|
-
it 'automaticallies set name off of nickname' do
|
113
|
-
allow(subject).to receive(:nickname).and_return('bob')
|
114
|
-
subject.info['name'] == 'bob'
|
115
|
-
end
|
116
|
-
|
117
|
-
it 'does not overwrite a provided name' do
|
118
|
-
allow(subject).to receive(:name).and_return('Awesome Dude')
|
119
|
-
allow(subject).to receive(:first_name).and_return('Frank')
|
120
|
-
expect(subject.info['name']).to eq('Awesome Dude')
|
39
|
+
it 'raises a NotImplementedError if the auth_key method is not defined' do
|
40
|
+
expect { instance.auth_key = 'broken' }.to raise_error(NotImplementedError)
|
121
41
|
end
|
122
42
|
end
|
123
43
|
end
|
@@ -1,11 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'sqlite3'
|
4
|
+
require 'active_record'
|
5
|
+
require 'anonymous_active_record'
|
6
|
+
|
7
|
+
class TestIdentity < OmniAuth::Identity::Models::ActiveRecord; end
|
8
|
+
|
9
|
+
RSpec.describe(OmniAuth::Identity::Models::ActiveRecord, sqlite3: true) do
|
4
10
|
describe 'model', type: :model do
|
5
11
|
subject(:model_klass) do
|
6
12
|
AnonymousActiveRecord.generate(
|
7
13
|
parent_klass: 'OmniAuth::Identity::Models::ActiveRecord',
|
8
|
-
columns: %w[
|
14
|
+
columns: OmniAuth::Identity::Model::SCHEMA_ATTRIBUTES | %w[provider password_digest],
|
9
15
|
connection_params: { adapter: 'sqlite3', encoding: 'utf8', database: ':memory:' }
|
10
16
|
) do
|
11
17
|
def flower
|
@@ -14,17 +20,20 @@ RSpec.describe(OmniAuth::Identity::Models::ActiveRecord, db: true) do
|
|
14
20
|
end
|
15
21
|
end
|
16
22
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
23
|
+
include_context 'persistable model'
|
24
|
+
|
25
|
+
describe '::table_name' do
|
26
|
+
it 'does not use STI rules for its table name' do
|
27
|
+
expect(TestIdentity.table_name).to eq('test_identities')
|
28
|
+
end
|
21
29
|
end
|
22
|
-
end
|
23
30
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
31
|
+
describe '::locate' do
|
32
|
+
it 'delegates locate to the where query method' do
|
33
|
+
allow(model_klass).to receive(:where).with('email' => 'open faced', 'category' => 'sandwiches',
|
34
|
+
'provider' => 'identity').and_return(['wakka'])
|
35
|
+
expect(model_klass.locate('email' => 'open faced', 'category' => 'sandwiches')).to eq('wakka')
|
36
|
+
end
|
28
37
|
end
|
29
38
|
end
|
30
39
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sqlite3'
|
4
|
+
require 'sequel'
|
5
|
+
|
6
|
+
DB = Sequel.sqlite
|
7
|
+
|
8
|
+
RSpec.describe(OmniAuth::Identity::Models::Sequel, sqlite3: true) do
|
9
|
+
before(:all) do
|
10
|
+
# Connect to an in-memory sqlite3 database.
|
11
|
+
DB.create_table :sequel_test_identities do
|
12
|
+
primary_key :id
|
13
|
+
String :email, null: false
|
14
|
+
String :password_digest, null: false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
sequel_test_identity = Class.new(Sequel::Model(:sequel_test_identities)) do
|
20
|
+
include ::OmniAuth::Identity::Models::Sequel
|
21
|
+
end
|
22
|
+
stub_const('SequelTestIdentity', sequel_test_identity)
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'model', type: :model do
|
26
|
+
subject(:model_klass) { SequelTestIdentity }
|
27
|
+
|
28
|
+
include_context 'persistable model'
|
29
|
+
|
30
|
+
describe '::locate' do
|
31
|
+
it 'delegates to the where query method' do
|
32
|
+
allow(model_klass).to receive(:where).with('email' => 'open faced',
|
33
|
+
'category' => 'sandwiches').and_return(['wakka'])
|
34
|
+
expect(model_klass.locate('email' => 'open faced', 'category' => 'sandwiches')).to eq('wakka')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,14 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'sqlite3'
|
4
|
+
require 'active_record'
|
5
|
+
require 'anonymous_active_record'
|
6
|
+
|
7
|
+
RSpec.describe OmniAuth::Strategies::Identity, sqlite3: true do
|
4
8
|
attr_accessor :app
|
5
9
|
|
6
|
-
let(:
|
7
|
-
let(:
|
10
|
+
let(:env_hash) { last_response.headers['env'] }
|
11
|
+
let(:auth_hash) { env_hash['omniauth.auth'] }
|
12
|
+
let(:identity_hash) { env_hash['omniauth.identity'] }
|
8
13
|
let(:identity_options) { {} }
|
9
14
|
let(:anon_ar) do
|
10
15
|
AnonymousActiveRecord.generate(
|
11
|
-
|
16
|
+
parent_klass: 'OmniAuth::Identity::Models::ActiveRecord',
|
17
|
+
columns: OmniAuth::Identity::Model::SCHEMA_ATTRIBUTES | %w[provider password_digest],
|
12
18
|
connection_params: { adapter: 'sqlite3', encoding: 'utf8', database: ':memory:' }
|
13
19
|
) do
|
14
20
|
def balloon
|
@@ -192,7 +198,7 @@ RSpec.describe OmniAuth::Strategies::Identity do
|
|
192
198
|
end
|
193
199
|
end
|
194
200
|
|
195
|
-
context 'with
|
201
|
+
context 'with good identity' do
|
196
202
|
let(:properties) do
|
197
203
|
{
|
198
204
|
name: 'Awesome Dude',
|
@@ -203,20 +209,71 @@ RSpec.describe OmniAuth::Strategies::Identity do
|
|
203
209
|
}
|
204
210
|
end
|
205
211
|
|
206
|
-
before do
|
207
|
-
allow(anon_ar).to receive('auth_key').and_return('email')
|
208
|
-
m = double(uid: 'abc', name: 'Awesome Dude', email: 'awesome@example.com',
|
209
|
-
info: { name: 'DUUUUDE!' }, persisted?: true)
|
210
|
-
expect(anon_ar).to receive(:create).with(properties).and_return(m)
|
211
|
-
end
|
212
|
-
|
213
212
|
it 'sets the auth hash' do
|
214
213
|
post '/auth/identity/register', properties
|
215
|
-
expect(auth_hash['uid']).to
|
214
|
+
expect(auth_hash['uid']).to match(/\d+/)
|
215
|
+
expect(auth_hash['provider']).to eq('identity')
|
216
|
+
end
|
217
|
+
|
218
|
+
context 'with on_validation proc' do
|
219
|
+
let(:identity_options) do
|
220
|
+
{ model: anon_ar, on_validation: on_validation_proc }
|
221
|
+
end
|
222
|
+
let(:on_validation_proc) do
|
223
|
+
lambda { |_env|
|
224
|
+
false
|
225
|
+
}
|
226
|
+
end
|
227
|
+
|
228
|
+
context 'when validation fails' do
|
229
|
+
it 'does not set the env hash' do
|
230
|
+
post '/auth/identity/register', properties
|
231
|
+
expect(env_hash).to eq(nil)
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'renders registration form' do
|
235
|
+
post '/auth/identity/register', properties
|
236
|
+
expect(last_response.body).to be_include(described_class.default_options[:registration_form_title])
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'displays validation failure message' do
|
240
|
+
post '/auth/identity/register', properties
|
241
|
+
expect(last_response.body).to be_include(described_class.default_options[:validation_failure_message])
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context 'when validation succeeds' do
|
246
|
+
let(:on_validation_proc) do
|
247
|
+
lambda { |_env|
|
248
|
+
true
|
249
|
+
}
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'sets the auth hash' do
|
253
|
+
post '/auth/identity/register', properties
|
254
|
+
expect(auth_hash['uid']).to match(/\d+/)
|
255
|
+
expect(auth_hash['provider']).to eq('identity')
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'does not render registration form' do
|
259
|
+
post '/auth/identity/register', properties
|
260
|
+
expect(last_response.body).not_to be_include(described_class.default_options[:registration_form_title])
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'does not display validation failure message' do
|
264
|
+
post '/auth/identity/register', properties
|
265
|
+
expect(last_response.body).not_to be_include(described_class.default_options[:validation_failure_message])
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'does not display registration failure message' do
|
269
|
+
post '/auth/identity/register', properties
|
270
|
+
expect(last_response.body).not_to be_include(described_class.default_options[:registration_failure_message])
|
271
|
+
end
|
272
|
+
end
|
216
273
|
end
|
217
274
|
end
|
218
275
|
|
219
|
-
context 'with
|
276
|
+
context 'with bad identity' do
|
220
277
|
let(:properties) do
|
221
278
|
{
|
222
279
|
name: 'Awesome Dude',
|
@@ -226,16 +283,17 @@ RSpec.describe OmniAuth::Strategies::Identity do
|
|
226
283
|
provider: 'identity'
|
227
284
|
}
|
228
285
|
end
|
229
|
-
let(:invalid_identity) { double(persisted?: false) }
|
286
|
+
let(:invalid_identity) { double(persisted?: false, save: false) }
|
230
287
|
|
231
288
|
before do
|
232
|
-
expect(anon_ar).to receive(:
|
289
|
+
expect(anon_ar).to receive(:new).with(properties).and_return(invalid_identity)
|
233
290
|
end
|
234
291
|
|
235
292
|
context 'default' do
|
236
293
|
it 'shows registration form' do
|
237
294
|
post '/auth/identity/register', properties
|
238
295
|
expect(last_response.body).to be_include('Register Identity')
|
296
|
+
expect(last_response.body).to be_include('One or more fields were invalid')
|
239
297
|
end
|
240
298
|
end
|
241
299
|
|
@@ -250,6 +308,63 @@ RSpec.describe OmniAuth::Strategies::Identity do
|
|
250
308
|
post '/auth/identity/register', properties
|
251
309
|
expect(identity_hash).to eq(invalid_identity)
|
252
310
|
expect(last_response.body).to be_include("FAIL'DOH!")
|
311
|
+
expect(last_response.body).not_to be_include('One or more fields were invalid')
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
context 'with on_validation proc' do
|
316
|
+
let(:identity_options) do
|
317
|
+
{ model: anon_ar, on_validation: on_validation_proc }
|
318
|
+
end
|
319
|
+
let(:on_validation_proc) do
|
320
|
+
lambda { |_env|
|
321
|
+
false
|
322
|
+
}
|
323
|
+
end
|
324
|
+
|
325
|
+
context 'when validation fails' do
|
326
|
+
it 'does not set the env hash' do
|
327
|
+
post '/auth/identity/register', properties
|
328
|
+
expect(env_hash).to eq(nil)
|
329
|
+
end
|
330
|
+
|
331
|
+
it 'renders registration form' do
|
332
|
+
post '/auth/identity/register', properties
|
333
|
+
expect(last_response.body).to be_include(described_class.default_options[:registration_form_title])
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'displays validation failure message' do
|
337
|
+
post '/auth/identity/register', properties
|
338
|
+
expect(last_response.body).to be_include(described_class.default_options[:validation_failure_message])
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
context 'when validation succeeds' do
|
343
|
+
let(:on_validation_proc) do
|
344
|
+
lambda { |_env|
|
345
|
+
true
|
346
|
+
}
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'does not set the env hash' do
|
350
|
+
post '/auth/identity/register', properties
|
351
|
+
expect(env_hash).to eq(nil)
|
352
|
+
end
|
353
|
+
|
354
|
+
it 'renders registration form' do
|
355
|
+
post '/auth/identity/register', properties
|
356
|
+
expect(last_response.body).to be_include(described_class.default_options[:registration_form_title])
|
357
|
+
end
|
358
|
+
|
359
|
+
it 'does not display validation failure message' do
|
360
|
+
post '/auth/identity/register', properties
|
361
|
+
expect(last_response.body).not_to be_include(described_class.default_options[:validation_failure_message])
|
362
|
+
end
|
363
|
+
|
364
|
+
it 'display registration failure message' do
|
365
|
+
post '/auth/identity/register', properties
|
366
|
+
expect(last_response.body).to be_include(described_class.default_options[:registration_failure_message])
|
367
|
+
end
|
253
368
|
end
|
254
369
|
end
|
255
370
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,20 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# NOTE: mongoid and no_brainer can't be loaded at the same time.
|
4
|
+
# If you try it, one or both of them will not work.
|
5
|
+
# This is why the ORM specs are split into a separate directory and run in separate threads.
|
6
|
+
|
7
|
+
ENV['RUBY_ENV'] = 'test' # Used by NoBrainer
|
8
|
+
ENV['MONGOID_ENV'] = 'test' # Used by Mongoid
|
9
|
+
|
3
10
|
ruby_version = Gem::Version.new(RUBY_VERSION)
|
4
11
|
require 'simplecov' if ruby_version >= Gem::Version.new('2.7') && RUBY_ENGINE == 'ruby'
|
5
12
|
|
6
13
|
require 'rack/test'
|
7
|
-
require '
|
8
|
-
require 'sqlite3'
|
9
|
-
require 'anonymous_active_record'
|
14
|
+
require 'rspec/block_is_expected'
|
10
15
|
require 'byebug' if RUBY_ENGINE == 'ruby'
|
11
16
|
|
12
17
|
# This gem
|
13
18
|
require 'omniauth/identity'
|
14
19
|
|
20
|
+
spec_root_matcher = %r{#{__dir__}/(.+)\.rb\Z}
|
21
|
+
Dir.glob(Pathname.new(__dir__).join('support/**/', '*.rb')).each { |f| require f.match(spec_root_matcher)[1] }
|
22
|
+
|
23
|
+
DEFAULT_PASSWORD = 'hang-a-left-at-the-diner'
|
24
|
+
DEFAULT_EMAIL = 'mojo@example.com'
|
25
|
+
|
15
26
|
RSpec.configure do |config|
|
16
27
|
config.include Rack::Test::Methods
|
17
|
-
|
28
|
+
|
29
|
+
# config.include ::Mongoid::Matchers, db: :mongodb
|
18
30
|
|
19
31
|
# Enable flags like --only-failures and --next-failure
|
20
32
|
config.example_status_persistence_file_path = '.rspec_status'
|