omniauth-multiprovider 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ */