sorcery 0.8.5 → 0.9.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 (163) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.travis.yml +122 -5
  4. data/CHANGELOG.md +37 -1
  5. data/Gemfile +10 -18
  6. data/README.md +159 -88
  7. data/gemfiles/active_record-rails40.gemfile +7 -0
  8. data/gemfiles/active_record-rails41.gemfile +7 -0
  9. data/gemfiles/mongo_mapper-rails40.gemfile +9 -0
  10. data/gemfiles/mongo_mapper-rails41.gemfile +9 -0
  11. data/gemfiles/mongoid-rails40.gemfile +9 -0
  12. data/gemfiles/mongoid-rails41.gemfile +9 -0
  13. data/gemfiles/mongoid3-rails32.gemfile +9 -0
  14. data/lib/generators/sorcery/USAGE +1 -1
  15. data/lib/generators/sorcery/install_generator.rb +19 -5
  16. data/lib/generators/sorcery/templates/initializer.rb +34 -9
  17. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +3 -1
  18. data/lib/generators/sorcery/templates/migration/core.rb +2 -2
  19. data/lib/generators/sorcery/templates/migration/external.rb +3 -1
  20. data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
  21. data/lib/sorcery/adapters/base_adapter.rb +30 -0
  22. data/lib/sorcery/adapters/data_mapper_adapter.rb +176 -0
  23. data/lib/sorcery/adapters/mongo_mapper_adapter.rb +110 -0
  24. data/lib/sorcery/adapters/mongoid_adapter.rb +97 -0
  25. data/lib/sorcery/controller/config.rb +65 -0
  26. data/lib/sorcery/controller/submodules/activity_logging.rb +16 -21
  27. data/lib/sorcery/controller/submodules/brute_force_protection.rb +6 -6
  28. data/lib/sorcery/controller/submodules/external.rb +35 -40
  29. data/lib/sorcery/controller/submodules/remember_me.rb +4 -4
  30. data/lib/sorcery/controller/submodules/session_timeout.rb +10 -6
  31. data/lib/sorcery/controller.rb +10 -74
  32. data/lib/sorcery/model/config.rb +96 -0
  33. data/lib/sorcery/model/submodules/activity_logging.rb +30 -13
  34. data/lib/sorcery/model/submodules/brute_force_protection.rb +21 -21
  35. data/lib/sorcery/model/submodules/external.rb +53 -9
  36. data/lib/sorcery/model/submodules/remember_me.rb +15 -19
  37. data/lib/sorcery/model/submodules/reset_password.rb +33 -34
  38. data/lib/sorcery/model/submodules/user_activation.rb +36 -47
  39. data/lib/sorcery/model/temporary_token.rb +4 -4
  40. data/lib/sorcery/model.rb +73 -173
  41. data/lib/sorcery/protocols/oauth.rb +42 -0
  42. data/lib/sorcery/protocols/oauth2.rb +47 -0
  43. data/lib/sorcery/providers/base.rb +38 -0
  44. data/lib/sorcery/providers/facebook.rb +63 -0
  45. data/lib/sorcery/providers/github.rb +51 -0
  46. data/lib/sorcery/providers/google.rb +51 -0
  47. data/lib/sorcery/providers/heroku.rb +57 -0
  48. data/lib/sorcery/providers/jira.rb +77 -0
  49. data/lib/sorcery/providers/linkedin.rb +66 -0
  50. data/lib/sorcery/providers/liveid.rb +53 -0
  51. data/lib/sorcery/providers/salesforce.rb +50 -0
  52. data/lib/sorcery/providers/twitter.rb +59 -0
  53. data/lib/sorcery/providers/vk.rb +63 -0
  54. data/lib/sorcery/providers/xing.rb +64 -0
  55. data/lib/sorcery/test_helpers/internal/rails.rb +14 -3
  56. data/lib/sorcery/test_helpers/internal.rb +7 -3
  57. data/lib/sorcery/test_helpers/rails/controller.rb +21 -0
  58. data/lib/sorcery/test_helpers/rails/integration.rb +26 -0
  59. data/lib/sorcery/version.rb +3 -0
  60. data/lib/sorcery.rb +82 -58
  61. data/sorcery.gemspec +19 -19
  62. data/spec/active_record/user_activation_spec.rb +1 -1
  63. data/spec/active_record/user_activity_logging_spec.rb +10 -1
  64. data/spec/active_record/user_brute_force_protection_spec.rb +1 -1
  65. data/spec/active_record/user_oauth_spec.rb +1 -1
  66. data/spec/active_record/user_remember_me_spec.rb +1 -1
  67. data/spec/active_record/user_reset_password_spec.rb +1 -1
  68. data/spec/active_record/user_spec.rb +7 -8
  69. data/spec/controllers/controller_activity_logging_spec.rb +124 -0
  70. data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
  71. data/spec/controllers/controller_http_basic_auth_spec.rb +68 -0
  72. data/spec/controllers/controller_oauth2_spec.rb +414 -0
  73. data/spec/controllers/controller_oauth_spec.rb +240 -0
  74. data/spec/controllers/controller_remember_me_spec.rb +117 -0
  75. data/spec/controllers/controller_session_timeout_spec.rb +80 -0
  76. data/spec/controllers/controller_spec.rb +218 -0
  77. data/spec/data_mapper/user_activation_spec.rb +10 -0
  78. data/spec/data_mapper/user_activity_logging_spec.rb +14 -0
  79. data/spec/data_mapper/user_brute_force_protection_spec.rb +9 -0
  80. data/spec/data_mapper/user_oauth_spec.rb +9 -0
  81. data/spec/data_mapper/user_remember_me_spec.rb +8 -0
  82. data/spec/data_mapper/user_reset_password_spec.rb +8 -0
  83. data/spec/data_mapper/user_spec.rb +27 -0
  84. data/spec/mongo_mapper/user_activation_spec.rb +1 -2
  85. data/spec/mongo_mapper/user_activity_logging_spec.rb +1 -1
  86. data/spec/mongo_mapper/user_brute_force_protection_spec.rb +1 -1
  87. data/spec/mongo_mapper/user_oauth_spec.rb +1 -1
  88. data/spec/mongo_mapper/user_remember_me_spec.rb +1 -1
  89. data/spec/mongo_mapper/user_reset_password_spec.rb +1 -1
  90. data/spec/mongo_mapper/user_spec.rb +7 -8
  91. data/spec/mongoid/user_activation_spec.rb +1 -2
  92. data/spec/mongoid/user_activity_logging_spec.rb +1 -2
  93. data/spec/mongoid/user_brute_force_protection_spec.rb +1 -2
  94. data/spec/mongoid/user_oauth_spec.rb +1 -2
  95. data/spec/mongoid/user_remember_me_spec.rb +1 -2
  96. data/spec/mongoid/user_reset_password_spec.rb +1 -2
  97. data/spec/mongoid/user_spec.rb +21 -9
  98. data/spec/orm/active_record.rb +14 -0
  99. data/spec/orm/data_mapper.rb +48 -0
  100. data/spec/orm/mongo_mapper.rb +1 -1
  101. data/spec/orm/mongoid.rb +5 -0
  102. data/spec/rails_app/app/controllers/sorcery_controller.rb +125 -59
  103. data/spec/rails_app/app/data_mapper/authentication.rb +8 -0
  104. data/spec/rails_app/app/data_mapper/user.rb +7 -0
  105. data/spec/rails_app/app/mongo_mapper/user.rb +2 -0
  106. data/spec/rails_app/config/routes.rb +27 -13
  107. data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +2 -2
  108. data/spec/shared_examples/user_activation_shared_examples.rb +108 -91
  109. data/spec/shared_examples/user_activity_logging_shared_examples.rb +83 -15
  110. data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +140 -21
  111. data/spec/shared_examples/user_oauth_shared_examples.rb +21 -16
  112. data/spec/shared_examples/user_remember_me_shared_examples.rb +36 -24
  113. data/spec/shared_examples/user_reset_password_shared_examples.rb +138 -117
  114. data/spec/shared_examples/user_shared_examples.rb +297 -150
  115. data/spec/sorcery_crypto_providers_spec.rb +28 -28
  116. data/spec/spec_helper.rb +12 -18
  117. metadata +99 -165
  118. data/Gemfile.rails4 +0 -24
  119. data/VERSION +0 -1
  120. data/lib/sorcery/controller/submodules/external/protocols/oauth1.rb +0 -46
  121. data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +0 -50
  122. data/lib/sorcery/controller/submodules/external/providers/base.rb +0 -21
  123. data/lib/sorcery/controller/submodules/external/providers/facebook.rb +0 -99
  124. data/lib/sorcery/controller/submodules/external/providers/github.rb +0 -93
  125. data/lib/sorcery/controller/submodules/external/providers/google.rb +0 -92
  126. data/lib/sorcery/controller/submodules/external/providers/linkedin.rb +0 -103
  127. data/lib/sorcery/controller/submodules/external/providers/liveid.rb +0 -93
  128. data/lib/sorcery/controller/submodules/external/providers/twitter.rb +0 -94
  129. data/lib/sorcery/controller/submodules/external/providers/vk.rb +0 -101
  130. data/lib/sorcery/controller/submodules/external/providers/xing.rb +0 -98
  131. data/lib/sorcery/model/adapters/active_record.rb +0 -49
  132. data/lib/sorcery/model/adapters/mongo_mapper.rb +0 -56
  133. data/lib/sorcery/model/adapters/mongoid.rb +0 -88
  134. data/lib/sorcery/test_helpers/rails.rb +0 -16
  135. data/lib/sorcery/test_helpers.rb +0 -5
  136. data/spec/active_record/controller_activity_logging_spec.rb +0 -140
  137. data/spec/active_record/controller_brute_force_protection_spec.rb +0 -136
  138. data/spec/active_record/controller_http_basic_auth_spec.rb +0 -59
  139. data/spec/active_record/controller_oauth2_spec.rb +0 -417
  140. data/spec/active_record/controller_oauth_spec.rb +0 -212
  141. data/spec/active_record/controller_remember_me_spec.rb +0 -96
  142. data/spec/active_record/controller_session_timeout_spec.rb +0 -55
  143. data/spec/active_record/controller_spec.rb +0 -182
  144. data/spec/active_record/integration_spec.rb +0 -23
  145. data/spec/mongo_mapper/controller_spec.rb +0 -175
  146. data/spec/mongoid/controller_activity_logging_spec.rb +0 -111
  147. data/spec/mongoid/controller_spec.rb +0 -186
  148. data/spec/rails_app/public/404.html +0 -26
  149. data/spec/rails_app/public/422.html +0 -26
  150. data/spec/rails_app/public/500.html +0 -26
  151. data/spec/rails_app/public/favicon.ico +0 -0
  152. data/spec/rails_app/public/images/rails.png +0 -0
  153. data/spec/rails_app/public/javascripts/application.js +0 -2
  154. data/spec/rails_app/public/javascripts/controls.js +0 -965
  155. data/spec/rails_app/public/javascripts/dragdrop.js +0 -974
  156. data/spec/rails_app/public/javascripts/effects.js +0 -1123
  157. data/spec/rails_app/public/javascripts/prototype.js +0 -6001
  158. data/spec/rails_app/public/javascripts/rails.js +0 -175
  159. data/spec/rails_app/public/robots.txt +0 -5
  160. data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
  161. data/spec/shared_examples/controller_oauth2_shared_examples.rb +0 -56
  162. data/spec/shared_examples/controller_oauth_shared_examples.rb +0 -69
  163. /data/lib/sorcery/{controller/submodules/external/protocols → protocols}/certs/ca-bundle.crt +0 -0
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe SorceryController do
4
+
5
+ let(:user) { double("user", id: 42, email: 'bla@bla.com') }
6
+
7
+ describe "with http basic auth features" do
8
+ before(:all) do
9
+ sorcery_reload!([:http_basic_auth])
10
+
11
+ sorcery_controller_property_set(:controller_to_realm_map, {"sorcery" => "sorcery"})
12
+ end
13
+
14
+ after(:each) do
15
+ logout_user
16
+ end
17
+
18
+ it "requests basic authentication when before_filter is used" do
19
+ get :test_http_basic_auth
20
+
21
+ expect(response.status).to eq 401
22
+ end
23
+
24
+ it "authenticates from http basic if credentials are sent" do
25
+ # dirty hack for rails 4
26
+ allow(subject).to receive(:register_last_activity_time_to_db)
27
+
28
+ @request.env["HTTP_AUTHORIZATION"] = "Basic #{Base64::encode64("#{user.email}:secret")}"
29
+ expect(User).to receive('authenticate').with('bla@bla.com', 'secret').and_return(user)
30
+ get :test_http_basic_auth, nil, http_authentication_used: true
31
+
32
+ expect(response).to be_a_success
33
+ end
34
+
35
+ it "fails authentication if credentials are wrong" do
36
+ @request.env["HTTP_AUTHORIZATION"] = "Basic #{Base64::encode64("#{user.email}:wrong!")}"
37
+ expect(User).to receive('authenticate').with('bla@bla.com', 'wrong!').and_return(nil)
38
+ get :test_http_basic_auth, nil, http_authentication_used: true
39
+
40
+ expect(response).to redirect_to root_url
41
+ end
42
+
43
+ it "allows configuration option 'controller_to_realm_map'" do
44
+ sorcery_controller_property_set(:controller_to_realm_map, {"1" => "2"})
45
+
46
+ expect(Sorcery::Controller::Config.controller_to_realm_map).to eq({"1" => "2"})
47
+ end
48
+
49
+ it "displays the correct realm name configured for the controller" do
50
+ sorcery_controller_property_set(:controller_to_realm_map, {"sorcery" => "Salad"})
51
+ get :test_http_basic_auth
52
+
53
+ expect(response.headers["WWW-Authenticate"]).to eq "Basic realm=\"Salad\""
54
+ end
55
+
56
+ it "signs in the user's session on successful login" do
57
+ # dirty hack for rails 4
58
+ allow(controller).to receive(:register_last_activity_time_to_db)
59
+
60
+ @request.env["HTTP_AUTHORIZATION"] = "Basic #{Base64::encode64("#{user.email}:secret")}"
61
+ expect(User).to receive('authenticate').with('bla@bla.com', 'secret').and_return(user)
62
+
63
+ get :test_http_basic_auth, nil, http_authentication_used: true
64
+
65
+ expect(session[:user_id]).to eq "42"
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,414 @@
1
+ require 'spec_helper'
2
+
3
+ # require 'shared_examples/controller_oauth2_shared_examples'
4
+
5
+ describe SorceryController, :active_record => true do
6
+ before(:all) do
7
+ if SORCERY_ORM == :active_record
8
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/external")
9
+ User.reset_column_information
10
+ end
11
+
12
+ sorcery_reload!([:external])
13
+ set_external_property
14
+ end
15
+
16
+ after(:all) do
17
+ if SORCERY_ORM == :active_record
18
+ ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/external")
19
+ end
20
+ end
21
+
22
+ describe 'using create_from' do
23
+ before(:each) do
24
+ stub_all_oauth2_requests!
25
+ end
26
+
27
+ it 'creates a new user' do
28
+ sorcery_model_property_set(:authentications_class, Authentication)
29
+ sorcery_controller_external_property_set(:facebook, :user_info_mapping, { username: 'name' })
30
+
31
+ expect(User).to receive(:create_from_provider).with('facebook', '123', {username: 'Noam Ben Ari'})
32
+ get :test_create_from_provider, provider: 'facebook'
33
+ end
34
+
35
+ it 'supports nested attributes' do
36
+ sorcery_model_property_set(:authentications_class, Authentication)
37
+ sorcery_controller_external_property_set(:facebook, :user_info_mapping, { username: 'hometown/name' })
38
+ expect(User).to receive(:create_from_provider).with('facebook', '123', {username: 'Haifa, Israel'})
39
+
40
+ get :test_create_from_provider, provider: 'facebook'
41
+ end
42
+
43
+ it 'does not crash on missing nested attributes' do
44
+ sorcery_model_property_set(:authentications_class, Authentication)
45
+ sorcery_controller_external_property_set(:facebook, :user_info_mapping, { username: 'name', created_at: 'does/not/exist' })
46
+
47
+ expect(User).to receive(:create_from_provider).with('facebook', '123', {username: 'Noam Ben Ari'})
48
+
49
+ get :test_create_from_provider, provider: 'facebook'
50
+ end
51
+
52
+ describe 'with a block' do
53
+ it 'does not create user' do
54
+ sorcery_model_property_set(:authentications_class, Authentication)
55
+ sorcery_controller_external_property_set(:facebook, :user_info_mapping, { username: 'name' })
56
+
57
+ u = double('user')
58
+ expect(User).to receive(:create_from_provider).with('facebook', '123', {username: 'Noam Ben Ari'}).and_return(u).and_yield(u)
59
+ # test_create_from_provider_with_block in controller will check for uniqueness of username
60
+ get :test_create_from_provider_with_block, provider: 'facebook'
61
+ end
62
+ end
63
+ end
64
+
65
+ # ----------------- OAuth -----------------------
66
+ context "with OAuth features" do
67
+
68
+ let(:user) { double('user', id: 42) }
69
+
70
+ before(:each) do
71
+ stub_all_oauth2_requests!
72
+ end
73
+
74
+ after(:each) do
75
+ User.sorcery_adapter.delete_all
76
+ Authentication.sorcery_adapter.delete_all
77
+ end
78
+
79
+ context "when callback_url begin with /" do
80
+ before do
81
+ sorcery_controller_external_property_set(:facebook, :callback_url, "/oauth/twitter/callback")
82
+ end
83
+ it "login_at redirects correctly" do
84
+ get :login_at_test_facebook
85
+ expect(response).to be_a_redirect
86
+ expect(response).to redirect_to("https://graph.facebook.com/oauth/authorize?client_id=#{::Sorcery::Controller::Config.facebook.key}&display=page&redirect_uri=http%3A%2F%2Ftest.host%2Foauth%2Ftwitter%2Fcallback&response_type=code&scope=email%2Coffline_access&state=")
87
+ end
88
+ it "logins with state" do
89
+ get :login_at_test_with_state
90
+ expect(response).to be_a_redirect
91
+ expect(response).to redirect_to("https://graph.facebook.com/oauth/authorize?client_id=#{::Sorcery::Controller::Config.facebook.key}&display=page&redirect_uri=http%3A%2F%2Ftest.host%2Foauth%2Ftwitter%2Fcallback&response_type=code&scope=email%2Coffline_access&state=bla")
92
+ end
93
+ after do
94
+ sorcery_controller_external_property_set(:facebook, :callback_url, "http://blabla.com")
95
+ end
96
+ end
97
+
98
+ #this test can never pass because of the previous test (the callback url can't change anymore)
99
+ =begin
100
+ context "when callback_url begin with http://" do
101
+ it "login_at redirects correctly" do
102
+ create_new_user
103
+ get :login_at_test2
104
+ response.should be_a_redirect
105
+ response.should redirect_to("https://graph.facebook.com/oauth/authorize?response_type=code&client_id=#{::Sorcery::Controller::Config.facebook.key}&redirect_uri=http%3A%2F%2Fblabla.com&scope=email%2Coffline_access&display=page&state")
106
+ end
107
+ end
108
+ =end
109
+ it "'login_from' logins if user exists" do
110
+ # dirty hack for rails 4
111
+ allow(subject).to receive(:register_last_activity_time_to_db)
112
+
113
+ sorcery_model_property_set(:authentications_class, Authentication)
114
+ expect(User).to receive(:load_from_provider).with(:facebook, '123').and_return(user)
115
+ get :test_login_from_facebook
116
+
117
+ expect(flash[:notice]).to eq "Success!"
118
+ end
119
+
120
+ it "'login_from' fails if user doesn't exist" do
121
+ sorcery_model_property_set(:authentications_class, Authentication)
122
+ expect(User).to receive(:load_from_provider).with(:facebook, '123').and_return(nil)
123
+ get :test_login_from_facebook
124
+
125
+ expect(flash[:alert]).to eq "Failed!"
126
+ end
127
+
128
+ it "on successful login_from the user is redirected to the url he originally wanted" do
129
+ # dirty hack for rails 4
130
+ allow(subject).to receive(:register_last_activity_time_to_db)
131
+
132
+ sorcery_model_property_set(:authentications_class, Authentication)
133
+ expect(User).to receive(:load_from_provider).with(:facebook, '123').and_return(user)
134
+ get :test_return_to_with_external_facebook, {}, :return_to_url => "fuu"
135
+
136
+ expect(response).to redirect_to("fuu")
137
+ expect(flash[:notice]).to eq "Success!"
138
+ end
139
+
140
+ [:github, :google, :liveid, :vk, :salesforce].each do |provider|
141
+
142
+ describe "with #{provider}" do
143
+
144
+ it "login_at redirects correctly" do
145
+ get :"login_at_test_#{provider}"
146
+
147
+ expect(response).to be_a_redirect
148
+ expect(response).to redirect_to(provider_url provider)
149
+ end
150
+
151
+ it "'login_from' logins if user exists" do
152
+ # dirty hack for rails 4
153
+ allow(subject).to receive(:register_last_activity_time_to_db)
154
+
155
+ sorcery_model_property_set(:authentications_class, Authentication)
156
+ expect(User).to receive(:load_from_provider).with(provider, '123').and_return(user)
157
+ get :"test_login_from_#{provider}"
158
+
159
+ expect(flash[:notice]).to eq "Success!"
160
+ end
161
+
162
+ it "'login_from' fails if user doesn't exist" do
163
+ sorcery_model_property_set(:authentications_class, Authentication)
164
+ expect(User).to receive(:load_from_provider).with(provider, '123').and_return(nil)
165
+ get :"test_login_from_#{provider}"
166
+
167
+ expect(flash[:alert]).to eq "Failed!"
168
+ end
169
+
170
+ it "on successful login_from the user is redirected to the url he originally wanted (#{provider})" do
171
+ # dirty hack for rails 4
172
+ allow(subject).to receive(:register_last_activity_time_to_db)
173
+
174
+ sorcery_model_property_set(:authentications_class, Authentication)
175
+ expect(User).to receive(:load_from_provider).with(provider, '123').and_return(user)
176
+ get :"test_return_to_with_external_#{provider}", {}, :return_to_url => "fuu"
177
+
178
+ expect(response).to redirect_to "fuu"
179
+ expect(flash[:notice]).to eq "Success!"
180
+ end
181
+ end
182
+ end
183
+
184
+ end
185
+
186
+ describe "OAuth with User Activation features" do
187
+ before(:all) do
188
+ if SORCERY_ORM == :active_record
189
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/activation")
190
+ end
191
+
192
+ sorcery_reload!([:user_activation,:external], :user_activation_mailer => ::SorceryMailer)
193
+ sorcery_controller_property_set(:external_providers, [:facebook, :github, :google, :liveid, :vk, :salesforce])
194
+
195
+ sorcery_controller_external_property_set(:facebook, :key, "eYVNBjBDi33aa9GkA3w")
196
+ sorcery_controller_external_property_set(:facebook, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
197
+ sorcery_controller_external_property_set(:facebook, :callback_url, "http://blabla.com")
198
+ sorcery_controller_external_property_set(:github, :key, "eYVNBjBDi33aa9GkA3w")
199
+ sorcery_controller_external_property_set(:github, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
200
+ sorcery_controller_external_property_set(:github, :callback_url, "http://blabla.com")
201
+ sorcery_controller_external_property_set(:google, :key, "eYVNBjBDi33aa9GkA3w")
202
+ sorcery_controller_external_property_set(:google, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
203
+ sorcery_controller_external_property_set(:google, :callback_url, "http://blabla.com")
204
+ sorcery_controller_external_property_set(:liveid, :key, "eYVNBjBDi33aa9GkA3w")
205
+ sorcery_controller_external_property_set(:liveid, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
206
+ sorcery_controller_external_property_set(:liveid, :callback_url, "http://blabla.com")
207
+ sorcery_controller_external_property_set(:vk, :key, "eYVNBjBDi33aa9GkA3w")
208
+ sorcery_controller_external_property_set(:vk, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
209
+ sorcery_controller_external_property_set(:vk, :callback_url, "http://blabla.com")
210
+ sorcery_controller_external_property_set(:salesforce, :key, "eYVNBjBDi33aa9GkA3w")
211
+ sorcery_controller_external_property_set(:salesforce, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
212
+ sorcery_controller_external_property_set(:salesforce, :callback_url, "http://blabla.com")
213
+ end
214
+
215
+ after(:all) do
216
+ if SORCERY_ORM == :active_record
217
+ ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/activation")
218
+ end
219
+ end
220
+
221
+ after(:each) do
222
+ User.sorcery_adapter.delete_all
223
+ end
224
+
225
+ it "does not send activation email to external users" do
226
+ old_size = ActionMailer::Base.deliveries.size
227
+ create_new_external_user(:facebook)
228
+
229
+ expect(ActionMailer::Base.deliveries.size).to eq old_size
230
+ end
231
+
232
+ it "does not send external users an activation success email" do
233
+ sorcery_model_property_set(:activation_success_email_method_name, nil)
234
+ create_new_external_user(:facebook)
235
+ old_size = ActionMailer::Base.deliveries.size
236
+ @user.activate!
237
+
238
+ expect(ActionMailer::Base.deliveries.size).to eq old_size
239
+ end
240
+
241
+ [:github, :google, :liveid, :vk, :salesforce].each do |provider|
242
+ it "does not send activation email to external users (#{provider})" do
243
+ old_size = ActionMailer::Base.deliveries.size
244
+ create_new_external_user provider
245
+ expect(ActionMailer::Base.deliveries.size).to eq old_size
246
+ end
247
+
248
+ it "does not send external users an activation success email (#{provider})" do
249
+ sorcery_model_property_set(:activation_success_email_method_name, nil)
250
+ create_new_external_user provider
251
+ old_size = ActionMailer::Base.deliveries.size
252
+ @user.activate!
253
+ end
254
+ end
255
+ end
256
+
257
+ describe "OAuth with user activation features" do
258
+
259
+ let(:user) { double('user', id: 42) }
260
+
261
+ before(:all) do
262
+ sorcery_reload!([:activity_logging, :external])
263
+ end
264
+
265
+ after(:all) do
266
+ if SORCERY_ORM == :active_record
267
+ ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/external")
268
+ ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/activity_logging")
269
+ end
270
+ end
271
+
272
+ %w(facebook github google liveid vk salesforce).each do |provider|
273
+ context "when #{provider}" do
274
+ before(:each) do
275
+ sorcery_controller_property_set(:register_login_time, true)
276
+ sorcery_controller_property_set(:register_logout_time, false)
277
+ sorcery_controller_property_set(:register_last_activity_time, false)
278
+ sorcery_controller_property_set(:register_last_ip_address, false)
279
+ stub_all_oauth2_requests!
280
+ sorcery_model_property_set(:authentications_class, Authentication)
281
+ end
282
+
283
+ it "registers login time" do
284
+ now = Time.now.in_time_zone
285
+ Timecop.freeze(now)
286
+ expect(User).to receive(:load_from_provider).and_return(user)
287
+ expect(user).to receive(:set_last_login_at).with(be_within(0.1).of(now))
288
+ get "test_login_from_#{provider}".to_sym
289
+ Timecop.return
290
+ end
291
+
292
+ it "does not register login time if configured so" do
293
+ sorcery_controller_property_set(:register_login_time, false)
294
+ now = Time.now.in_time_zone
295
+ Timecop.freeze(now)
296
+ expect(User).to receive(:load_from_provider).and_return(user)
297
+ expect(user).to receive(:set_last_login_at).never
298
+ get "test_login_from_#{provider}".to_sym
299
+
300
+ end
301
+ end
302
+ end
303
+ end
304
+
305
+ describe "OAuth with session timeout features" do
306
+ before(:all) do
307
+ sorcery_reload!([:session_timeout, :external])
308
+ end
309
+
310
+ let(:user) { double('user', id: 42) }
311
+
312
+ %w(facebook github google liveid vk salesforce).each do |provider|
313
+ context "when #{provider}" do
314
+ before(:each) do
315
+ sorcery_model_property_set(:authentications_class, Authentication)
316
+ sorcery_controller_property_set(:session_timeout,0.5)
317
+ stub_all_oauth2_requests!
318
+ end
319
+
320
+ after(:each) do
321
+ Timecop.return
322
+ end
323
+
324
+ it "does not reset session before session timeout" do
325
+ expect(User).to receive(:load_from_provider).with(provider.to_sym, '123').and_return(user)
326
+ get "test_login_from_#{provider}".to_sym
327
+
328
+ expect(session[:user_id]).not_to be_nil
329
+ expect(flash[:notice]).to eq "Success!"
330
+ end
331
+
332
+ it "resets session after session timeout" do
333
+ expect(User).to receive(:load_from_provider).with(provider.to_sym, '123').and_return(user)
334
+ get "test_login_from_#{provider}".to_sym
335
+ expect(session[:user_id]).to eq "42"
336
+ Timecop.travel(Time.now.in_time_zone+0.6)
337
+ get :test_should_be_logged_in
338
+
339
+ expect(session[:user_id]).to be_nil
340
+ expect(response).to be_a_redirect
341
+ end
342
+ end
343
+ end
344
+ end
345
+
346
+ def stub_all_oauth2_requests!
347
+ access_token = double(OAuth2::AccessToken)
348
+ allow(access_token).to receive(:token_param=)
349
+ response = double(OAuth2::Response)
350
+ allow(response).to receive(:body) { {
351
+ "id"=>"123",
352
+ "user_id"=>"123", # Needed for Salesforce
353
+ "name"=>"Noam Ben Ari",
354
+ "first_name"=>"Noam",
355
+ "last_name"=>"Ben Ari",
356
+ "link"=>"http://www.facebook.com/nbenari1",
357
+ "hometown"=>{"id"=>"110619208966868", "name"=>"Haifa, Israel"},
358
+ "location"=>{"id"=>"106906559341067", "name"=>"Pardes Hanah, Hefa, Israel"},
359
+ "bio"=>"I'm a new daddy, and enjoying it!",
360
+ "gender"=>"male",
361
+ "email"=>"nbenari@gmail.com",
362
+ "timezone"=>2,
363
+ "locale"=>"en_US",
364
+ "languages"=>[{"id"=>"108405449189952", "name"=>"Hebrew"}, {"id"=>"106059522759137", "name"=>"English"}, {"id"=>"112624162082677", "name"=>"Russian"}],
365
+ "verified"=>true,
366
+ "updated_time"=>"2011-02-16T20:59:38+0000",
367
+ # response for VK auth
368
+ "response"=>[
369
+ {
370
+ "uid"=>"123",
371
+ "first_name"=>"Noam",
372
+ "last_name"=>"Ben Ari"
373
+ }
374
+ ]}.to_json }
375
+ allow(access_token).to receive(:get) { response }
376
+ allow(access_token).to receive(:token) { "187041a618229fdaf16613e96e1caabc1e86e46bbfad228de41520e63fe45873684c365a14417289599f3" }
377
+ # access_token params for VK auth
378
+ allow(access_token).to receive(:params) { { "user_id"=>"100500", "email"=>"nbenari@gmail.com" } }
379
+ allow_any_instance_of(OAuth2::Strategy::AuthCode).to receive(:get_token) { access_token }
380
+ end
381
+
382
+ def set_external_property
383
+ sorcery_controller_property_set(:external_providers, [:facebook, :github, :google, :liveid, :vk, :salesforce])
384
+ sorcery_controller_external_property_set(:facebook, :key, "eYVNBjBDi33aa9GkA3w")
385
+ sorcery_controller_external_property_set(:facebook, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
386
+ sorcery_controller_external_property_set(:facebook, :callback_url, "http://blabla.com")
387
+ sorcery_controller_external_property_set(:github, :key, "eYVNBjBDi33aa9GkA3w")
388
+ sorcery_controller_external_property_set(:github, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
389
+ sorcery_controller_external_property_set(:github, :callback_url, "http://blabla.com")
390
+ sorcery_controller_external_property_set(:google, :key, "eYVNBjBDi33aa9GkA3w")
391
+ sorcery_controller_external_property_set(:google, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
392
+ sorcery_controller_external_property_set(:google, :callback_url, "http://blabla.com")
393
+ sorcery_controller_external_property_set(:liveid, :key, "eYVNBjBDi33aa9GkA3w")
394
+ sorcery_controller_external_property_set(:liveid, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
395
+ sorcery_controller_external_property_set(:liveid, :callback_url, "http://blabla.com")
396
+ sorcery_controller_external_property_set(:vk, :key, "eYVNBjBDi33aa9GkA3w")
397
+ sorcery_controller_external_property_set(:vk, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
398
+ sorcery_controller_external_property_set(:vk, :callback_url, "http://blabla.com")
399
+ sorcery_controller_external_property_set(:salesforce, :key, "eYVNBjBDi33aa9GkA3w")
400
+ sorcery_controller_external_property_set(:salesforce, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
401
+ sorcery_controller_external_property_set(:salesforce, :callback_url, "http://blabla.com")
402
+ end
403
+
404
+ def provider_url(provider)
405
+ {
406
+ github: "https://github.com/login/oauth/authorize?client_id=#{::Sorcery::Controller::Config.github.key}&display=&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=&state=",
407
+ google: "https://accounts.google.com/o/oauth2/auth?client_id=#{::Sorcery::Controller::Config.google.key}&display=&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&state=",
408
+ liveid: "https://oauth.live.com/authorize?client_id=#{::Sorcery::Controller::Config.liveid.key}&display=&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=wl.basic+wl.emails+wl.offline_access&state=",
409
+ vk: "https://oauth.vk.com/authorize?client_id=#{::Sorcery::Controller::Config.vk.key}&display=&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=#{::Sorcery::Controller::Config.vk.scope}&state=",
410
+ salesforce: "https://login.salesforce.com/services/oauth2/authorize?client_id=#{::Sorcery::Controller::Config.salesforce.key}&display=&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=#{::Sorcery::Controller::Config.salesforce.scope}&state="
411
+ }[provider]
412
+ end
413
+ end
414
+