omniauth-multiprovider 0.1.1 → 0.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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +13 -18
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +4 -0
  7. data/{LICENSE → LICENSE.txt} +0 -0
  8. data/README.md +52 -7
  9. data/Rakefile +2 -0
  10. data/lib/omniauth-multiprovider.rb +3 -1
  11. data/lib/omniauth/multiprovider.rb +0 -1
  12. data/lib/omniauth/multiprovider/config.rb +25 -0
  13. data/lib/omniauth/multiprovider/controllers/callbacks_controller.rb +43 -3
  14. data/lib/omniauth/multiprovider/error.rb +24 -1
  15. data/lib/omniauth/multiprovider/models/active_record.rb +14 -0
  16. data/lib/omniauth/multiprovider/models/authentication.rb +1 -9
  17. data/lib/omniauth/multiprovider/models/concerns/omni_authenticable.rb +79 -32
  18. data/lib/omniauth/multiprovider/version.rb +1 -1
  19. data/lib/omniauth/provider/abstract.rb +6 -38
  20. data/lib/omniauth/provider/generic.rb +10 -13
  21. data/omniauth-multiprovider.gemspec +15 -2
  22. data/spec/omniauth/error_spec.rb +30 -0
  23. data/spec/omniauth/multiprovider/controllers/callbacks_controller_spec.rb +90 -0
  24. data/spec/omniauth/multiprovider/models/active_record_spec.rb +21 -0
  25. data/spec/omniauth/multiprovider/models/concerns/omni_authenticable_spec.rb +67 -0
  26. data/spec/omniauth/provider/abstract_spec.rb +15 -0
  27. data/spec/omniauth/provider/facebook_spec.rb +13 -0
  28. data/spec/omniauth/provider/generic_spec.rb +13 -0
  29. data/spec/rails_app/.gitignore +17 -0
  30. data/spec/rails_app/Rakefile +6 -0
  31. data/spec/rails_app/app/assets/images/.keep +0 -0
  32. data/spec/rails_app/app/assets/javascripts/application.js +16 -0
  33. data/spec/rails_app/app/assets/stylesheets/application.css +15 -0
  34. data/spec/rails_app/app/controllers/application_controller.rb +5 -0
  35. data/spec/rails_app/app/controllers/concerns/.keep +0 -0
  36. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  37. data/spec/rails_app/app/mailers/.keep +0 -0
  38. data/spec/rails_app/app/models/.keep +0 -0
  39. data/spec/rails_app/app/models/concerns/.keep +0 -0
  40. data/spec/rails_app/app/models/user.rb +4 -0
  41. data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
  42. data/spec/rails_app/bin/bundle +3 -0
  43. data/spec/rails_app/bin/rails +4 -0
  44. data/spec/rails_app/bin/rake +4 -0
  45. data/spec/rails_app/bin/setup +29 -0
  46. data/spec/rails_app/config.ru +4 -0
  47. data/spec/rails_app/config/application.rb +26 -0
  48. data/spec/rails_app/config/boot.rb +3 -0
  49. data/spec/rails_app/config/database.yml +25 -0
  50. data/spec/rails_app/config/environment.rb +5 -0
  51. data/spec/rails_app/config/environments/test.rb +42 -0
  52. data/spec/rails_app/config/initializers/assets.rb +11 -0
  53. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  54. data/spec/rails_app/config/initializers/cookies_serializer.rb +3 -0
  55. data/spec/rails_app/config/initializers/devise.rb +259 -0
  56. data/spec/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
  57. data/spec/rails_app/config/initializers/inflections.rb +16 -0
  58. data/spec/rails_app/config/initializers/mime_types.rb +4 -0
  59. data/spec/rails_app/config/initializers/session_store.rb +3 -0
  60. data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
  61. data/spec/rails_app/config/locales/en.yml +23 -0
  62. data/spec/rails_app/config/routes.rb +3 -0
  63. data/spec/rails_app/config/secrets.yml +22 -0
  64. data/spec/rails_app/db/seeds.rb +7 -0
  65. data/spec/rails_app/lib/assets/.keep +0 -0
  66. data/spec/rails_app/lib/tasks/.keep +0 -0
  67. data/spec/rails_app/public/404.html +67 -0
  68. data/spec/rails_app/public/422.html +67 -0
  69. data/spec/rails_app/public/500.html +66 -0
  70. data/spec/rails_app/public/favicon.ico +0 -0
  71. data/spec/rails_app/public/robots.txt +5 -0
  72. data/spec/spec_helper.rb +43 -0
  73. data/spec/support/shared_examples_for_providers.rb +27 -0
  74. metadata +226 -7
  75. data/lib/omniauth/multiprovider/helpers.rb +0 -23
  76. data/lib/omniauth/provider/guests.rb +0 -12
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module MultiProvider
3
- VERSION = '0.1.1'
3
+ VERSION = '0.2.0'
4
4
  end
5
5
  end
@@ -1,46 +1,14 @@
1
1
  module OmniAuth
2
2
  module Provider
3
- class Abstract
3
+ class Abstract < SimpleDelegator
4
4
 
5
- def self.init
5
+ def initialize(controller)
6
+ super
7
+ @controller = controller
6
8
  end
7
9
 
8
- OmniAuth::MultiProvider::resource_klass.send(:include, OmniAuth::MultiProvider::EmailMockups)
9
-
10
- def self.find_from_oauth(provider_name, omniauth_data, signed_in_resource=nil)
11
- auth = MultiProvider::authentication_klass.normalize(omniauth_data)
12
- access_token = auth.credentials.token
13
- authentication = MultiProvider.authentication_klass.find_by(provider: provider_name, uid: auth.uid)
14
-
15
- resource = nil
16
-
17
- if authentication
18
- if signed_in_resource
19
- if authentication.resource == signed_in_resource
20
- raise MultiProvider::Error.new 'already connected'
21
- else
22
- raise MultiProvider::Error.new 'already connected with other user'
23
- end
24
- end
25
- resource = authentication.resource
26
- end
27
- unless resource
28
- if auth.info[:email].blank?
29
- auth.info[:email] = MultiProvider::resource_klass.mock_email(provider_name, auth.uid)
30
- end
31
- email = auth.info[:email]
32
-
33
- raise MultiProvider::Error.new 'email_already_registered' if MultiProvider::resource_klass.find_by(email: email)
34
-
35
- resource = signed_in_resource || MultiProvider::resource_klass.new(
36
- email: email,
37
- password: Devise.friendly_token[0,20]
38
- )
39
-
40
- MultiProvider.authentication_klass.from(auth, resource)
41
-
42
- end
43
- resource
10
+ def handle_request(controller)
11
+ raise "Should be defined by subclasses"
44
12
  end
45
13
 
46
14
  def self.authenticate_from_oauth(provider_name, omniauth_data)
@@ -2,21 +2,18 @@ module OmniAuth
2
2
  module Provider
3
3
  class Generic < Abstract
4
4
 
5
- def self.init(provider_name)
6
- klass = self
7
- OmniAuth::MultiProvider::CallbacksController.add_callback(provider_name) do
8
- auth = request.env['omniauth.auth']
9
- resource = klass.find_from_oauth(provider_name, auth, send(OmniAuth::MultiProvider::current_resource))
10
- if resource.persisted?
11
- sign_in_and_redirect resource, event: :authentication #this will throw if resource is not activated
12
- set_flash_message(:notice, :success, kind: provider_name.to_s.camelize) if is_navigational_format?
13
- else
14
- session["devise.#{provider_name}_data"] = auth.except('extra')
15
- redirect_to send("new_#{OmniAuth::MultiProvider::resource_mapping}_registration_url")
16
- end
5
+ def handle_request
6
+ auth = request.env['omniauth.auth']
7
+ provider_name = auth['provider_name']
8
+ resource = resource_class.from_oauth auth, signed_in_resource
9
+ if resource.persisted?
10
+ sign_in_and_redirect resource, event: :authentication #this will throw if resource is not activated
11
+ @controller.send(:set_flash_message, :notice, :success, kind: provider_name.to_s.camelize) if is_navigational_format?
12
+ else
13
+ session["devise.#{provider_name}_data"] = auth.except('extra')
14
+ redirect_to send("new_#{OmniAuth::MultiProvider::resource_mapping}_registration_url")
17
15
  end
18
16
  end
19
-
20
17
  end
21
18
  end
22
19
  end
@@ -1,4 +1,7 @@
1
- $:.push File.expand_path('../lib', __FILE__)
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
2
5
  require 'omniauth/multiprovider/version'
3
6
 
4
7
  Gem::Specification.new do |s|
@@ -8,12 +11,22 @@ Gem::Specification.new do |s|
8
11
  s.description = "Provides a simple approach to support many oauth providers to devise"
9
12
  s.authors = ["German Del Zotto"]
10
13
  s.email = 'germ@ndz.com.ar'
11
- s.files = `git ls-files`.split("\n")
14
+ s.files = `git ls-files -z`.split("\x0")
15
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
12
16
  s.require_paths = ['lib']
13
17
  s.homepage = 'https://github.com/1uptalent/omniauth-multiprovider'
14
18
  s.license = 'MIT'
15
19
 
16
20
  s.add_dependency('devise', '~> 3.2')
21
+ s.add_dependency('activesupport', ">= 3.2.6", "< 5")
22
+ s.add_dependency('activerecord', ">= 3.2.6", "< 5")
17
23
  s.add_dependency('omniauth-oauth2', '~> 1.1')
18
24
  s.add_dependency('hashugar', '~> 0.0', '>= 0.0.6')
25
+
26
+ s.add_development_dependency "bundler", "~> 1.7"
27
+ s.add_development_dependency "rake", "~> 10.0"
28
+
29
+ s.add_development_dependency "rspec", "~> 3.1"
30
+ s.add_development_dependency "rspec-rails", "~> 3.1"
31
+ s.add_development_dependency "sqlite3"
19
32
  end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe OmniAuth::MultiProvider::Error do
4
+ it 'is a runtime error' do
5
+ expect { raise OmniAuth::MultiProvider::Error }.to raise_error RuntimeError
6
+ end
7
+ end
8
+
9
+ describe OmniAuth::MultiProvider::AlreadyBoundError do
10
+ let(:current_resource) { double('current_resource') }
11
+ let(:bound_resource) { double("bound_resource") }
12
+
13
+ it 'provides the current and bound resources' do
14
+ error = OmniAuth::MultiProvider::AlreadyBoundError.new(current_resource, bound_resource)
15
+ expect(error.bound_to).to be bound_resource
16
+ expect(error.current).to be current_resource
17
+ end
18
+
19
+ describe '#message' do
20
+ it 'is "bound_to_same" for the same current and bound resource' do
21
+ error = OmniAuth::MultiProvider::AlreadyBoundError.new(current_resource, current_resource)
22
+ expect(error.message).to eq 'bound_to_same'
23
+ end
24
+
25
+ it 'is "bound_to_other" for different current and bound resources' do
26
+ error = OmniAuth::MultiProvider::AlreadyBoundError.new(current_resource, bound_resource)
27
+ expect(error.message).to eq 'bound_to_other'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'OmniAuth::MultiProvider::CallbacksController' do
4
+ let(:klass) { OmniAuth::MultiProvider::CallbacksController }
5
+
6
+ it 'defines methods for omniauth providers' do
7
+ Devise.omniauth :foo
8
+ Devise.omniauth :bar
9
+ methods = klass.action_methods
10
+ expect(methods).to include 'foo'
11
+ expect(methods).to include 'bar'
12
+ end
13
+
14
+ describe '#create_handler' do
15
+ it 'creates a method with the handler name' do
16
+ klass.send :create_handler, 'whatever'
17
+ expect(klass.action_methods).to include 'whatever'
18
+ end
19
+
20
+ it 'creates a generic handler for unknown providers' do
21
+ expect_any_instance_of(OmniAuth::Provider::Generic).to receive :handle_request
22
+ klass.send :create_handler, 'whatever'
23
+ klass.new.whatever
24
+ end
25
+
26
+ it 'creates a custom handler for Facebook' do
27
+ expect_any_instance_of(OmniAuth::Provider::Facebook).to receive :handle_request
28
+ klass.send :create_handler, 'facebook'
29
+ klass.new.facebook
30
+ end
31
+ end
32
+
33
+ describe '#handle_request' do
34
+ subject { klass.new }
35
+ let(:request) { ActionDispatch::TestRequest.new }
36
+ let(:response) { ActionDispatch::TestResponse.new }
37
+ before { klass.send :public, :handle_request }
38
+ before { allow(subject).to receive(:devise_mapping) { Devise.mappings[:user]} }
39
+ before do
40
+ subject.instance_variable_set '@_request', request
41
+ subject.instance_variable_set '@_response', response
42
+ end
43
+
44
+ context 'when it raises' do
45
+ let(:provider) { double('a provider') }
46
+
47
+ context 'MultiProvider errors' do
48
+ let(:error) { OmniAuth::MultiProvider::Error.new 'message_key' }
49
+ before { expect(provider).to receive(:handle_request).and_raise(error) }
50
+
51
+ context 'default behavior' do
52
+ it 'does not raise' do
53
+ expect { subject.handle_request provider }.not_to raise_error
54
+ end
55
+
56
+ it 'sets the flash[:alert] with an I18N error message' do
57
+ subject.handle_request provider
58
+ expect(subject.flash[:alert]).to match %r{en.devise.callbacks.user.#{error.message}}
59
+ end
60
+
61
+ it 'redirects to the remembered url' do
62
+ location = '/foo/bar/baz'
63
+ subject.store_location_for :user, location
64
+ subject.handle_request provider
65
+ expect(response.location).to eq "http://test.host#{location}"
66
+ end
67
+ end
68
+
69
+ it 'does raise if the error is not handled' do
70
+ allow(subject).to receive(:handle_provider_error) { false }
71
+ expect { subject.handle_request provider }.to raise_error error
72
+ end
73
+ end
74
+
75
+ context 'unexpected errors' do
76
+ let(:unexpected_error) { Class.new(RuntimeError).new("some message") }
77
+ before { expect(provider).to receive(:handle_request).and_raise(unexpected_error) }
78
+ it 're-raises the error by default' do
79
+ expect { subject.handle_request provider }.to raise_error unexpected_error
80
+ end
81
+ it 'does not raise if the error is handled' do
82
+ allow(subject).to receive(:handle_unexpected_error) { true }
83
+ expect { subject.handle_request provider }.not_to raise_error
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+
90
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe OmniAuth::MultiProvider::ActiveRecord do
4
+ before do
5
+ ActiveRecord::Base.connection.create_table :cs, temporary: true
6
+ end
7
+ after do
8
+ ActiveRecord::Base.connection.drop_table :cs
9
+ end
10
+ let!(:klass) do
11
+ class C < ActiveRecord::Base
12
+ omniauthenticable
13
+ end
14
+ end
15
+
16
+ it 'can create instances' do
17
+ klass.new
18
+ end
19
+
20
+
21
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe OmniAuth::MultiProvider::OmniAuthenticable do
4
+ describe '#from_oauth' do
5
+ context 'already authenticated' do
6
+ let(:user) do
7
+ u = User.new
8
+ u.save validate: false
9
+ u
10
+ end
11
+ let(:authentication) do
12
+ Authentication.create(resource: user, provider: 'test', uid: '123')
13
+ end
14
+ let(:omniauth_data) do
15
+ #https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
16
+ {
17
+ provider: authentication.provider,
18
+ uid: authentication.uid,
19
+ credentials: { token: 'foo' }
20
+ }
21
+ end
22
+
23
+ it 'returns the existing user' do
24
+ expected = user
25
+ actual = User.from_oauth omniauth_data
26
+ expect(expected).to eq actual
27
+ end
28
+
29
+ it 'fails if the current user is different' do
30
+ another_user = User.new
31
+ expect do
32
+ User.from_oauth omniauth_data, another_user
33
+ end.to raise_error OmniAuth::MultiProvider::AlreadyBoundError
34
+ end
35
+
36
+ it 'succeeds if already bound to current user' do
37
+ expect do
38
+ User.from_oauth omniauth_data, user
39
+ end.not_to raise_error
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '#oauth_to_attributes' do
45
+ it 'returns email, password and password_confirmation' do
46
+ oauth = {provider: 'foo', info: { email: 'some_email' } }.to_hashugar
47
+ attrs = User.oauth_to_attributes oauth
48
+ expect(attrs.keys).to match [:email, :password, :password_confirmation]
49
+ end
50
+
51
+ it 'returns a mock email when oauth data does not have it' do
52
+ oauth = {provider: 'foo', info: {} }.to_hashugar
53
+ email = User.oauth_to_attributes(oauth)[:email]
54
+ expect(email).to match /@from-foo\.example$/
55
+ end
56
+
57
+ it 'returns the oauth email if present' do
58
+ oauth = {provider: 'foo', info: {email: 'smith@example.com'} }.to_hashugar
59
+ email = User.oauth_to_attributes(oauth)[:email]
60
+ expect(email).to eq 'smith@example.com'
61
+ end
62
+ end
63
+
64
+ describe '#update_from_oauth' do
65
+
66
+ end
67
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ require 'support/shared_examples_for_providers'
3
+
4
+ describe OmniAuth::Provider::Abstract do
5
+ let(:controller) { double('a controller') }
6
+ subject { described_class.new controller }
7
+
8
+ it_behaves_like 'a provider'
9
+
10
+ describe '#handle_request' do
11
+ it 'raises since it is a template method' do
12
+ expect{subject.handle_request double('controller')}.to raise_error "Should be defined by subclasses"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'support/shared_examples_for_providers'
3
+
4
+ describe OmniAuth::Provider::Facebook do
5
+ let(:controller) { double('a controller') }
6
+ subject { described_class.new controller }
7
+
8
+ it_behaves_like 'a provider'
9
+
10
+ describe '#handle_request' do
11
+ end
12
+
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'support/shared_examples_for_providers'
3
+
4
+ describe OmniAuth::Provider::Generic do
5
+ let(:controller) { double('a controller') }
6
+ subject { described_class.new controller }
7
+
8
+ it_behaves_like 'a provider'
9
+
10
+ describe '#handle_request' do
11
+ end
12
+
13
+ end
@@ -0,0 +1,17 @@
1
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.bundle
9
+
10
+ # Ignore the default SQLite database.
11
+ /db/*.sqlite3
12
+ /db/*.sqlite3-journal
13
+
14
+ # Ignore all logfiles and tempfiles.
15
+ /log/*
16
+ !/log/.keep
17
+ /tmp
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
File without changes
@@ -0,0 +1,16 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require turbolinks
16
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */