cbsorcery 0.8.6

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 (135) hide show
  1. data/.document +5 -0
  2. data/.gitignore +56 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +40 -0
  5. data/CHANGELOG.md +263 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.md +360 -0
  9. data/Rakefile +6 -0
  10. data/gemfiles/active_record-rails40.gemfile +7 -0
  11. data/gemfiles/active_record-rails41.gemfile +7 -0
  12. data/lib/generators/sorcery/USAGE +22 -0
  13. data/lib/generators/sorcery/helpers.rb +40 -0
  14. data/lib/generators/sorcery/install_generator.rb +95 -0
  15. data/lib/generators/sorcery/templates/initializer.rb +451 -0
  16. data/lib/generators/sorcery/templates/migration/activity_logging.rb +10 -0
  17. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +9 -0
  18. data/lib/generators/sorcery/templates/migration/core.rb +13 -0
  19. data/lib/generators/sorcery/templates/migration/external.rb +12 -0
  20. data/lib/generators/sorcery/templates/migration/remember_me.rb +8 -0
  21. data/lib/generators/sorcery/templates/migration/reset_password.rb +9 -0
  22. data/lib/generators/sorcery/templates/migration/user_activation.rb +9 -0
  23. data/lib/sorcery.rb +85 -0
  24. data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
  25. data/lib/sorcery/adapters/base_adapter.rb +30 -0
  26. data/lib/sorcery/controller.rb +157 -0
  27. data/lib/sorcery/controller/config.rb +65 -0
  28. data/lib/sorcery/controller/submodules/activity_logging.rb +82 -0
  29. data/lib/sorcery/controller/submodules/brute_force_protection.rb +38 -0
  30. data/lib/sorcery/controller/submodules/external.rb +199 -0
  31. data/lib/sorcery/controller/submodules/http_basic_auth.rb +74 -0
  32. data/lib/sorcery/controller/submodules/remember_me.rb +81 -0
  33. data/lib/sorcery/controller/submodules/session_timeout.rb +56 -0
  34. data/lib/sorcery/crypto_providers/aes256.rb +51 -0
  35. data/lib/sorcery/crypto_providers/bcrypt.rb +97 -0
  36. data/lib/sorcery/crypto_providers/common.rb +35 -0
  37. data/lib/sorcery/crypto_providers/md5.rb +19 -0
  38. data/lib/sorcery/crypto_providers/sha1.rb +28 -0
  39. data/lib/sorcery/crypto_providers/sha256.rb +36 -0
  40. data/lib/sorcery/crypto_providers/sha512.rb +36 -0
  41. data/lib/sorcery/engine.rb +21 -0
  42. data/lib/sorcery/model.rb +183 -0
  43. data/lib/sorcery/model/config.rb +96 -0
  44. data/lib/sorcery/model/submodules/activity_logging.rb +70 -0
  45. data/lib/sorcery/model/submodules/brute_force_protection.rb +125 -0
  46. data/lib/sorcery/model/submodules/external.rb +100 -0
  47. data/lib/sorcery/model/submodules/remember_me.rb +62 -0
  48. data/lib/sorcery/model/submodules/reset_password.rb +131 -0
  49. data/lib/sorcery/model/submodules/user_activation.rb +149 -0
  50. data/lib/sorcery/model/temporary_token.rb +30 -0
  51. data/lib/sorcery/protocols/certs/ca-bundle.crt +5182 -0
  52. data/lib/sorcery/protocols/oauth.rb +42 -0
  53. data/lib/sorcery/protocols/oauth2.rb +47 -0
  54. data/lib/sorcery/providers/base.rb +27 -0
  55. data/lib/sorcery/providers/facebook.rb +63 -0
  56. data/lib/sorcery/providers/github.rb +51 -0
  57. data/lib/sorcery/providers/google.rb +51 -0
  58. data/lib/sorcery/providers/jira.rb +77 -0
  59. data/lib/sorcery/providers/linkedin.rb +66 -0
  60. data/lib/sorcery/providers/liveid.rb +53 -0
  61. data/lib/sorcery/providers/twitter.rb +59 -0
  62. data/lib/sorcery/providers/vk.rb +63 -0
  63. data/lib/sorcery/providers/xing.rb +64 -0
  64. data/lib/sorcery/railties/tasks.rake +6 -0
  65. data/lib/sorcery/test_helpers/internal.rb +78 -0
  66. data/lib/sorcery/test_helpers/internal/rails.rb +68 -0
  67. data/lib/sorcery/test_helpers/rails/controller.rb +21 -0
  68. data/lib/sorcery/test_helpers/rails/integration.rb +26 -0
  69. data/lib/sorcery/version.rb +3 -0
  70. data/sorcery.gemspec +34 -0
  71. data/spec/active_record/user_activation_spec.rb +18 -0
  72. data/spec/active_record/user_activity_logging_spec.rb +17 -0
  73. data/spec/active_record/user_brute_force_protection_spec.rb +16 -0
  74. data/spec/active_record/user_oauth_spec.rb +16 -0
  75. data/spec/active_record/user_remember_me_spec.rb +16 -0
  76. data/spec/active_record/user_reset_password_spec.rb +16 -0
  77. data/spec/active_record/user_spec.rb +37 -0
  78. data/spec/controllers/controller_activity_logging_spec.rb +124 -0
  79. data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
  80. data/spec/controllers/controller_http_basic_auth_spec.rb +68 -0
  81. data/spec/controllers/controller_oauth2_spec.rb +407 -0
  82. data/spec/controllers/controller_oauth_spec.rb +240 -0
  83. data/spec/controllers/controller_remember_me_spec.rb +117 -0
  84. data/spec/controllers/controller_session_timeout_spec.rb +80 -0
  85. data/spec/controllers/controller_spec.rb +215 -0
  86. data/spec/orm/active_record.rb +21 -0
  87. data/spec/rails_app/app/active_record/authentication.rb +3 -0
  88. data/spec/rails_app/app/active_record/user.rb +5 -0
  89. data/spec/rails_app/app/active_record/user_provider.rb +3 -0
  90. data/spec/rails_app/app/controllers/sorcery_controller.rb +265 -0
  91. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  92. data/spec/rails_app/app/mailers/sorcery_mailer.rb +32 -0
  93. data/spec/rails_app/app/views/application/index.html.erb +17 -0
  94. data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
  95. data/spec/rails_app/app/views/sorcery_mailer/activation_email.html.erb +17 -0
  96. data/spec/rails_app/app/views/sorcery_mailer/activation_email.text.erb +9 -0
  97. data/spec/rails_app/app/views/sorcery_mailer/activation_needed_email.html.erb +17 -0
  98. data/spec/rails_app/app/views/sorcery_mailer/activation_success_email.html.erb +17 -0
  99. data/spec/rails_app/app/views/sorcery_mailer/activation_success_email.text.erb +9 -0
  100. data/spec/rails_app/app/views/sorcery_mailer/reset_password_email.html.erb +16 -0
  101. data/spec/rails_app/app/views/sorcery_mailer/reset_password_email.text.erb +8 -0
  102. data/spec/rails_app/app/views/sorcery_mailer/send_unlock_token_email.text.erb +1 -0
  103. data/spec/rails_app/config.ru +4 -0
  104. data/spec/rails_app/config/application.rb +56 -0
  105. data/spec/rails_app/config/boot.rb +4 -0
  106. data/spec/rails_app/config/database.yml +22 -0
  107. data/spec/rails_app/config/environment.rb +5 -0
  108. data/spec/rails_app/config/environments/test.rb +37 -0
  109. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  110. data/spec/rails_app/config/initializers/inflections.rb +10 -0
  111. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  112. data/spec/rails_app/config/initializers/secret_token.rb +7 -0
  113. data/spec/rails_app/config/initializers/session_store.rb +12 -0
  114. data/spec/rails_app/config/locales/en.yml +5 -0
  115. data/spec/rails_app/config/routes.rb +48 -0
  116. data/spec/rails_app/db/migrate/activation/20101224223622_add_activation_to_users.rb +17 -0
  117. data/spec/rails_app/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +19 -0
  118. data/spec/rails_app/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +13 -0
  119. data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +16 -0
  120. data/spec/rails_app/db/migrate/external/20101224223628_create_authentications_and_user_providers.rb +22 -0
  121. data/spec/rails_app/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +15 -0
  122. data/spec/rails_app/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +13 -0
  123. data/spec/rails_app/db/schema.rb +23 -0
  124. data/spec/rails_app/db/seeds.rb +7 -0
  125. data/spec/shared_examples/user_activation_shared_examples.rb +242 -0
  126. data/spec/shared_examples/user_activity_logging_shared_examples.rb +97 -0
  127. data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +156 -0
  128. data/spec/shared_examples/user_oauth_shared_examples.rb +36 -0
  129. data/spec/shared_examples/user_remember_me_shared_examples.rb +57 -0
  130. data/spec/shared_examples/user_reset_password_shared_examples.rb +263 -0
  131. data/spec/shared_examples/user_shared_examples.rb +467 -0
  132. data/spec/sorcery_crypto_providers_spec.rb +198 -0
  133. data/spec/spec.opts +2 -0
  134. data/spec/spec_helper.rb +41 -0
  135. metadata +350 -0
@@ -0,0 +1,240 @@
1
+ require 'spec_helper'
2
+
3
+ # require 'shared_examples/controller_oauth_shared_examples'
4
+ require 'ostruct'
5
+
6
+ def stub_all_oauth_requests!
7
+ consumer = OAuth::Consumer.new("key","secret", :site => "http://myapi.com")
8
+ req_token = OAuth::RequestToken.new(consumer)
9
+ acc_token = OAuth::AccessToken.new(consumer)
10
+
11
+ response = OpenStruct.new()
12
+ response.body = {"following"=>false, "listed_count"=>0, "profile_link_color"=>"0084B4", "profile_image_url"=>"http://a1.twimg.com/profile_images/536178575/noamb_normal.jpg", "description"=>"Programmer/Heavy Metal Fan/New Father", "status"=>{"text"=>"coming soon to sorcery gem: twitter and facebook authentication support.", "truncated"=>false, "favorited"=>false, "source"=>"web", "geo"=>nil, "in_reply_to_screen_name"=>nil, "in_reply_to_user_id"=>nil, "in_reply_to_status_id_str"=>nil, "created_at"=>"Sun Mar 06 23:01:12 +0000 2011", "contributors"=>nil, "place"=>nil, "retweeted"=>false, "in_reply_to_status_id"=>nil, "in_reply_to_user_id_str"=>nil, "coordinates"=>nil, "retweet_count"=>0, "id"=>44533012284706816, "id_str"=>"44533012284706816"}, "show_all_inline_media"=>false, "geo_enabled"=>true, "profile_sidebar_border_color"=>"a8c7f7", "url"=>nil, "followers_count"=>10, "screen_name"=>"nbenari", "profile_use_background_image"=>true, "location"=>"Israel", "statuses_count"=>25, "profile_background_color"=>"022330", "lang"=>"en", "verified"=>false, "notifications"=>false, "profile_background_image_url"=>"http://a3.twimg.com/profile_background_images/104087198/04042010339.jpg", "favourites_count"=>5, "created_at"=>"Fri Nov 20 21:58:19 +0000 2009", "is_translator"=>false, "contributors_enabled"=>false, "protected"=>false, "follow_request_sent"=>false, "time_zone"=>"Greenland", "profile_text_color"=>"333333", "name"=>"Noam Ben Ari", "friends_count"=>10, "profile_sidebar_fill_color"=>"C0DFEC", "id"=>123, "id_str"=>"91434812", "profile_background_tile"=>false, "utc_offset"=>-10800}.to_json
13
+
14
+ session[:request_token] = req_token.token
15
+ session[:request_token_secret] = req_token.secret
16
+
17
+ allow(OAuth::Consumer).to receive(:new) { consumer }
18
+ allow(consumer).to receive(:get_request_token) { req_token }
19
+ allow(req_token).to receive(:get_access_token) { acc_token }
20
+ allow(OAuth::RequestToken).to receive(:new) { req_token }
21
+ allow(acc_token).to receive(:get) { response }
22
+ end
23
+
24
+ describe SorceryController do
25
+
26
+ let(:user) { double('user', id: 42) }
27
+
28
+ before(:all) do
29
+ sorcery_reload!([:external])
30
+ sorcery_controller_property_set(:external_providers, [:twitter, :jira])
31
+ sorcery_controller_external_property_set(:twitter, :key, "eYVNBjBDi33aa9GkA3w")
32
+ sorcery_controller_external_property_set(:twitter, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
33
+ sorcery_controller_external_property_set(:twitter, :callback_url, "http://blabla.com")
34
+
35
+ sorcery_controller_external_property_set(:jira, :key, "7810b8e317ebdc81601c72f8daecc0f1")
36
+ sorcery_controller_external_property_set(:jira, :secret, "MyAppUsingJira")
37
+ sorcery_controller_external_property_set(:jira, :site, "http://jira.mycompany.com/plugins/servlet/oauth")
38
+ sorcery_controller_external_property_set(:jira, :signature_method, "RSA-SHA1")
39
+ sorcery_controller_external_property_set(:jira, :private_key_file, "myrsakey.pem")
40
+ sorcery_controller_external_property_set(:jira, :callback_url, "http://myappusingjira.com/home")
41
+ end
42
+
43
+ # ----------------- OAuth -----------------------
44
+ describe SorceryController, "'using external API to login'" do
45
+
46
+ before(:each) do
47
+ stub_all_oauth_requests!
48
+ end
49
+
50
+ context "when callback_url begin with /" do
51
+ before do
52
+ sorcery_controller_external_property_set(:twitter, :callback_url, "/oauth/twitter/callback")
53
+ end
54
+ it "login_at redirects correctly" do
55
+ get :login_at_test
56
+ expect(response).to be_a_redirect
57
+ expect(response).to redirect_to("http://myapi.com/oauth/authorize?oauth_callback=http%3A%2F%2Ftest.host%2Foauth%2Ftwitter%2Fcallback&oauth_token=")
58
+ end
59
+ after do
60
+ sorcery_controller_external_property_set(:twitter, :callback_url, "http://blabla.com")
61
+ end
62
+ end
63
+
64
+ context "when callback_url begin with http://" do
65
+ it "login_at redirects correctly", pending: true do
66
+ get :login_at_test
67
+ expect(response).to be_a_redirect
68
+ expect(response).to redirect_to("http://myapi.com/oauth/authorize?oauth_callback=http%3A%2F%2Fblabla.com&oauth_token=")
69
+ end
70
+ end
71
+
72
+ it "logins if user exists" do
73
+ expect(User).to receive(:load_from_provider).with(:twitter, '123').and_return(user)
74
+
75
+ get :test_login_from, :oauth_verifier => "blablaRERASDFcxvSDFA"
76
+ expect(flash[:notice]).to eq "Success!"
77
+ end
78
+
79
+ it "'login_from' fails if user doesn't exist" do
80
+ expect(User).to receive(:load_from_provider).with(:twitter, '123').and_return(nil)
81
+
82
+ get :test_login_from, :oauth_verifier => "blablaRERASDFcxvSDFA"
83
+ expect(flash[:alert]).to eq "Failed!"
84
+ end
85
+
86
+ it "on successful 'login_from' the user is redirected to the url he originally wanted" do
87
+ expect(User).to receive(:load_from_provider).with(:twitter, '123').and_return(user)
88
+ get :test_return_to_with_external, {}, :return_to_url => "fuu"
89
+ expect(response).to redirect_to("fuu")
90
+ expect(flash[:notice]).to eq "Success!"
91
+ end
92
+
93
+ context "when jira" do
94
+ it "user logins successfully" do
95
+ get :login_at_test_jira
96
+ expect(session[:request_token]).not_to be_nil
97
+ expect(response).to be_a_redirect
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ describe SorceryController do
104
+ describe "using 'create_from'" do
105
+ before(:each) do
106
+ stub_all_oauth_requests!
107
+ end
108
+
109
+ it "creates a new user" do
110
+ sorcery_controller_external_property_set(:twitter, :user_info_mapping, {:username => "screen_name"})
111
+ expect(User).to receive(:load_from_provider).with('twitter', '123').and_return(nil)
112
+ expect(User).to receive(:create_from_provider).with('twitter', '123', {username: 'nbenari'}).and_return(user)
113
+
114
+ get :test_create_from_provider, :provider => "twitter"
115
+ end
116
+
117
+ it "supports nested attributes" do
118
+ sorcery_controller_external_property_set(:twitter, :user_info_mapping, {:username => "status/text"})
119
+ expect(User).to receive(:load_from_provider).with('twitter', '123').and_return(nil)
120
+ expect(User).to receive(:create_from_provider).with('twitter', '123', {username: 'coming soon to sorcery gem: twitter and facebook authentication support.'}).and_return(user)
121
+
122
+ get :test_create_from_provider, :provider => "twitter"
123
+ end
124
+
125
+ it "does not crash on missing nested attributes" do
126
+ sorcery_controller_external_property_set(:twitter, :user_info_mapping, {:username => "status/text", :created_at => "does/not/exist"})
127
+ expect(User).to receive(:load_from_provider).with('twitter', '123').and_return(nil)
128
+ expect(User).to receive(:create_from_provider).with('twitter', '123', {username: 'coming soon to sorcery gem: twitter and facebook authentication support.'}).and_return(user)
129
+
130
+ get :test_create_from_provider, :provider => "twitter"
131
+ end
132
+
133
+ it "binds new provider" do
134
+ sorcery_model_property_set(:authentications_class, UserProvider)
135
+
136
+ allow(user).to receive_message_chain(:sorcery_config, :username_attribute_names, :first) { :username }
137
+ allow(user).to receive(:username).and_return('bla@bla.com')
138
+ login_user(user)
139
+
140
+ expect(user).to receive(:add_provider_to_user).with('twitter', '123')
141
+ get :test_add_second_provider, :provider => "twitter"
142
+ end
143
+
144
+ describe "with a block" do
145
+ it "does not create user" do
146
+ sorcery_model_property_set(:authentications_class, Authentication)
147
+ sorcery_controller_external_property_set(:twitter, :user_info_mapping, {:username => "screen_name"})
148
+
149
+ u = double('user')
150
+ expect(User).to receive(:load_from_provider).with('twitter', '123').and_return(nil)
151
+ expect(User).to receive(:create_from_provider).with('twitter', '123', {username: 'nbenari'}).and_return(u).and_yield(u)
152
+
153
+ get :test_create_from_provider_with_block, :provider => "twitter"
154
+ end
155
+
156
+ end
157
+ end
158
+ end
159
+
160
+ describe SorceryController, "OAuth with user activation features" do
161
+ before(:all) do
162
+ sorcery_reload!([:activity_logging, :external])
163
+ end
164
+
165
+ context "when twitter" do
166
+ before(:each) do
167
+ sorcery_controller_property_set(:register_login_time, true)
168
+ sorcery_controller_property_set(:register_logout_time, false)
169
+ sorcery_controller_property_set(:register_last_activity_time, false)
170
+ sorcery_controller_property_set(:register_last_ip_address, false)
171
+ stub_all_oauth_requests!
172
+ end
173
+
174
+ it "registers login time" do
175
+ now = Time.now.in_time_zone
176
+ Timecop.freeze(now)
177
+ expect(User).to receive(:load_from_provider).and_return(user)
178
+ expect(user).to receive(:set_last_login_at).with(be_within(0.1).of(now))
179
+ get :test_login_from
180
+ Timecop.return
181
+ end
182
+
183
+ it "does not register login time if configured so" do
184
+ sorcery_controller_property_set(:register_login_time, false)
185
+ now = Time.now.in_time_zone
186
+ Timecop.freeze(now)
187
+ expect(User).to receive(:load_from_provider).and_return(user)
188
+ expect(user).to receive(:set_last_login_at).never
189
+ get :test_login_from
190
+ Timecop.return
191
+ end
192
+ end
193
+ end
194
+
195
+ describe SorceryController, "OAuth with session timeout features" do
196
+ before(:all) do
197
+ if SORCERY_ORM == :active_record
198
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/external")
199
+ User.reset_column_information
200
+ end
201
+
202
+ sorcery_reload!([:session_timeout, :external])
203
+ end
204
+
205
+ after(:all) do
206
+ if SORCERY_ORM == :active_record
207
+ ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/external")
208
+ end
209
+ end
210
+
211
+ context "when twitter" do
212
+ before(:each) do
213
+ sorcery_model_property_set(:authentications_class, Authentication)
214
+ sorcery_controller_property_set(:session_timeout,0.5)
215
+ stub_all_oauth_requests!
216
+ end
217
+
218
+ after(:each) do
219
+ Timecop.return
220
+ end
221
+
222
+ it "does not reset session before session timeout" do
223
+ expect(User).to receive(:load_from_provider).with(:twitter, '123').and_return(user)
224
+ get :test_login_from
225
+
226
+ expect(session[:user_id]).not_to be_nil
227
+ expect(flash[:notice]).to eq "Success!"
228
+ end
229
+
230
+ it "resets session after session timeout" do
231
+ get :test_login_from
232
+ Timecop.travel(Time.now.in_time_zone+0.6)
233
+ get :test_should_be_logged_in
234
+
235
+ expect(session[:user_id]).to be_nil
236
+ expect(response).to be_a_redirect
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe SorceryController do
4
+
5
+ let!(:user) { double('user', id: 42) }
6
+
7
+ # ----------------- REMEMBER ME -----------------------
8
+ context "with remember me features" do
9
+
10
+ before(:all) do
11
+ sorcery_reload!([:remember_me])
12
+ end
13
+
14
+ after(:each) do
15
+ session = nil
16
+ cookies = nil
17
+ end
18
+
19
+ before(:each) do
20
+ allow(user).to receive(:remember_me_token)
21
+ allow(user).to receive(:remember_me_token_expires_at)
22
+ allow(user).to receive_message_chain(:sorcery_config, :remember_me_token_attribute_name).and_return(:remember_me_token)
23
+ allow(user).to receive_message_chain(:sorcery_config, :remember_me_token_expires_at_attribute_name).and_return(:remember_me_token_expires_at)
24
+ end
25
+
26
+ it "sets cookie on remember_me!" do
27
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
28
+ expect(user).to receive(:remember_me!)
29
+
30
+ post :test_login_with_remember, :email => 'bla@bla.com', :password => 'secret'
31
+
32
+ expect(cookies.signed["remember_me_token"]).to eq assigns[:current_user].remember_me_token
33
+ end
34
+
35
+ it "clears cookie on forget_me!" do
36
+ cookies["remember_me_token"] == {:value => 'asd54234dsfsd43534', :expires => 3600}
37
+ get :test_logout
38
+
39
+ expect(cookies["remember_me_token"]).to be_nil
40
+ end
41
+
42
+ it "login(email,password,remember_me) logs user in and remembers" do
43
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret', '1').and_return(user)
44
+ expect(user).to receive(:remember_me!)
45
+ expect(user).to receive(:remember_me_token).and_return('abracadabra').twice
46
+
47
+ post :test_login_with_remember_in_login, :email => 'bla@bla.com', :password => 'secret', :remember => "1"
48
+
49
+ expect(cookies.signed["remember_me_token"]).not_to be_nil
50
+ expect(cookies.signed["remember_me_token"]).to eq assigns[:user].remember_me_token
51
+ end
52
+
53
+ it "logout also calls forget_me!" do
54
+ session[:user_id] = user.id.to_s
55
+ expect(User.sorcery_adapter).to receive(:find_by_id).with(user.id.to_s).and_return(user)
56
+ expect(user).to receive(:remember_me!)
57
+ expect(user).to receive(:forget_me!)
58
+ get :test_logout_with_remember
59
+
60
+ expect(cookies["remember_me_token"]).to be_nil
61
+ end
62
+
63
+ it "logs user in from cookie" do
64
+ session[:user_id] = user.id.to_s
65
+ expect(User.sorcery_adapter).to receive(:find_by_id).with(user.id.to_s).and_return(user)
66
+ expect(user).to receive(:remember_me!)
67
+ expect(user).to receive(:remember_me_token).and_return('token').twice
68
+ expect(user).to receive(:has_remember_me_token?) { true }
69
+
70
+ subject.remember_me!
71
+ subject.instance_eval do
72
+ remove_instance_variable :@current_user
73
+ end
74
+ session[:user_id] = nil
75
+
76
+ expect(User.sorcery_adapter).to receive(:find_by_remember_me_token).with('token').and_return(user)
77
+
78
+ get :test_login_from_cookie
79
+
80
+ expect(assigns[:current_user]).to eq user
81
+ end
82
+
83
+ it "doest not remember_me! when not asked to, even if third parameter is used" do
84
+ post :test_login_with_remember_in_login, :email => 'bla@bla.com', :password => 'secret', :remember => "0"
85
+
86
+ expect(cookies["remember_me_token"]).to be_nil
87
+ end
88
+
89
+ it "doest not remember_me! when not asked to" do
90
+ post :test_login, :email => 'bla@bla.com', :password => 'secret'
91
+ expect(cookies["remember_me_token"]).to be_nil
92
+ end
93
+
94
+ # --- login_user(user) ---
95
+ specify { expect(@controller).to respond_to :auto_login }
96
+
97
+ it "auto_login(user) logs in an user instance without remembering" do
98
+ session[:user_id] = nil
99
+ subject.auto_login(user)
100
+ get :test_login_from_cookie
101
+
102
+ expect(assigns[:current_user]).to eq user
103
+ expect(cookies["remember_me_token"]).to be_nil
104
+ end
105
+
106
+ it "auto_login(user, true) logs in an user instance with remembering" do
107
+ session[:user_id] = nil
108
+ expect(user).to receive(:remember_me!)
109
+ subject.auto_login(user, true)
110
+
111
+ get :test_login_from_cookie
112
+
113
+ expect(assigns[:current_user]).to eq user
114
+ expect(cookies["remember_me_token"]).not_to be_nil
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe SorceryController do
4
+
5
+ let!(:user) { double('user', id: 42) }
6
+
7
+ # ----------------- SESSION TIMEOUT -----------------------
8
+ context "with session timeout features" do
9
+ before(:all) do
10
+ sorcery_reload!([:session_timeout])
11
+ sorcery_controller_property_set(:session_timeout,0.5)
12
+ end
13
+
14
+ after(:each) do
15
+ Timecop.return
16
+ end
17
+
18
+ before(:each) do
19
+ allow(user).to receive(:username)
20
+ allow(user).to receive_message_chain(:sorcery_config, :username_attribute_names, :first) { :username }
21
+ end
22
+
23
+ it "does not reset session before session timeout" do
24
+ login_user user
25
+ get :test_should_be_logged_in
26
+
27
+ expect(session[:user_id]).not_to be_nil
28
+ expect(response).to be_a_success
29
+ end
30
+
31
+ it "resets session after session timeout" do
32
+ login_user user
33
+ Timecop.travel(Time.now.in_time_zone+0.6)
34
+ get :test_should_be_logged_in
35
+
36
+ expect(session[:user_id]).to be_nil
37
+ expect(response).to be_a_redirect
38
+ end
39
+
40
+ it "works if the session is stored as a string or a Time" do
41
+ session[:login_time] = Time.now.to_s
42
+ # TODO: ???
43
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
44
+
45
+ get :test_login, :email => 'bla@bla.com', :password => 'secret'
46
+
47
+ expect(session[:user_id]).not_to be_nil
48
+ expect(response).to be_a_success
49
+ end
50
+
51
+ context "with 'session_timeout_from_last_action'" do
52
+ it "does not logout if there was activity" do
53
+ sorcery_controller_property_set(:session_timeout_from_last_action, true)
54
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
55
+
56
+ get :test_login, :email => 'bla@bla.com', :password => 'secret'
57
+ Timecop.travel(Time.now.in_time_zone+0.3)
58
+ get :test_should_be_logged_in
59
+
60
+ expect(session[:user_id]).not_to be_nil
61
+
62
+ Timecop.travel(Time.now.in_time_zone+0.3)
63
+ get :test_should_be_logged_in
64
+
65
+ expect(session[:user_id]).not_to be_nil
66
+ expect(response).to be_a_success
67
+ end
68
+
69
+ it "with 'session_timeout_from_last_action' logs out if there was no activity" do
70
+ sorcery_controller_property_set(:session_timeout_from_last_action, true)
71
+ get :test_login, :email => 'bla@bla.com', :password => 'secret'
72
+ Timecop.travel(Time.now.in_time_zone+0.6)
73
+ get :test_should_be_logged_in
74
+
75
+ expect(session[:user_id]).to be_nil
76
+ expect(response).to be_a_redirect
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,215 @@
1
+ require 'spec_helper'
2
+
3
+ describe SorceryController do
4
+ describe "plugin configuration" do
5
+ before(:all) do
6
+ sorcery_reload!
7
+ end
8
+
9
+ after(:each) do
10
+ Sorcery::Controller::Config.reset!
11
+ sorcery_reload!
12
+ end
13
+
14
+ it "enables configuration option 'user_class'" do
15
+ sorcery_controller_property_set(:user_class, "TestUser")
16
+
17
+ expect(Sorcery::Controller::Config.user_class).to eq "TestUser"
18
+ end
19
+
20
+ it "enables configuration option 'not_authenticated_action'" do
21
+ sorcery_controller_property_set(:not_authenticated_action, :my_action)
22
+
23
+ expect(Sorcery::Controller::Config.not_authenticated_action).to eq :my_action
24
+ end
25
+
26
+ end
27
+
28
+ # ----------------- PLUGIN ACTIVATED -----------------------
29
+ context "when activated with sorcery" do
30
+ let(:user) { double('user', id: 42) }
31
+
32
+ before(:all) do
33
+ sorcery_reload!
34
+ end
35
+
36
+ after(:each) do
37
+ Sorcery::Controller::Config.reset!
38
+ sorcery_reload!
39
+ sorcery_controller_property_set(:user_class, User)
40
+ sorcery_model_property_set(:username_attribute_names, [:email])
41
+ end
42
+
43
+ specify { should respond_to(:login) }
44
+
45
+ specify { should respond_to(:logout) }
46
+
47
+ specify { should respond_to(:logged_in?) }
48
+
49
+ specify { should respond_to(:current_user) }
50
+
51
+ it "login(username,password) returns the user when success and set the session with user.id" do
52
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
53
+
54
+ get :test_login, :email => 'bla@bla.com', :password => 'secret'
55
+
56
+ expect(assigns[:user]).to eq user
57
+ expect(session[:user_id]).to eq "42"
58
+ end
59
+
60
+ it "login(email,password) returns the user when success and set the session with user.id" do
61
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
62
+
63
+ get :test_login, :email => 'bla@bla.com', :password => 'secret'
64
+
65
+ expect(assigns[:user]).to eq user
66
+ expect(session[:user_id]).to eq user.id.to_s
67
+ end
68
+
69
+ it "login(username,password) returns nil and not set the session when failure" do
70
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'opensesame!').and_return(nil)
71
+
72
+ get :test_login, :email => 'bla@bla.com', :password => 'opensesame!'
73
+
74
+ expect(assigns[:user]).to be_nil
75
+ expect(session[:user_id]).to be_nil
76
+ end
77
+
78
+ it "login(email,password) returns the user when success and set the session with the _csrf_token" do
79
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
80
+ get :test_login, :email => 'bla@bla.com', :password => 'secret'
81
+
82
+ expect(session[:_csrf_token]).not_to be_nil
83
+ end
84
+
85
+ it "login(username,password) returns nil and not set the session when upper case username" do
86
+ get :test_login, :email => 'BLA@BLA.COM', :password => 'secret'
87
+
88
+ expect(assigns[:user]).to be_nil
89
+ expect(session[:user_id]).to be_nil
90
+ end
91
+
92
+ # TODO: move test to model
93
+ it "login(username,password) returns the user and set the session with user.id when upper case username and config is downcase before authenticating" do
94
+ sorcery_model_property_set(:downcase_username_before_authenticating, true)
95
+ expect(User).to receive(:authenticate).with('BLA@BLA.COM', 'secret').and_return(user)
96
+ get :test_login, :email => 'BLA@BLA.COM', :password => 'secret'
97
+
98
+ expect(assigns[:user]).to eq user
99
+ expect(session[:user_id]).to eq user.id.to_s
100
+ end
101
+
102
+ # TODO: move test to model
103
+ it "login(username,password) returns nil and not set the session when user was created with upper case username, config is default, and log in username is lower case" do
104
+ expect(User).to receive(:authenticate).with('bla1@bla.com', 'secret1').and_return(nil)
105
+ get :test_login, :email => 'bla1@bla.com', :password => 'secret1'
106
+
107
+ expect(assigns[:user]).to be_nil
108
+ expect(session[:user_id]).to be_nil
109
+ end
110
+
111
+ # TODO: move test to model
112
+ it "login(username,password) returns the user and set the session with user.id when user was created with upper case username and config is downcase before authenticating" do
113
+ sorcery_model_property_set(:downcase_username_before_authenticating, true)
114
+ expect(User).to receive(:authenticate).with('bla1@bla.com', 'secret1').and_return(user)
115
+ get :test_login, :email => 'bla1@bla.com', :password => 'secret1'
116
+
117
+ expect(assigns[:user]).to eq user
118
+ expect(session[:user_id]).to eq user.id.to_s
119
+ end
120
+
121
+ it "logout clears the session" do
122
+ cookies[:remember_me_token] = nil
123
+ session[:user_id] = user.id.to_s
124
+ expect(User.sorcery_adapter).to receive(:find_by_id).with("42") { user }
125
+ get :test_logout
126
+
127
+ expect(session[:user_id]).to be_nil
128
+ end
129
+
130
+ it "logged_in? returns true if logged in" do
131
+ session[:user_id] = user.id.to_s
132
+ expect(User.sorcery_adapter).to receive(:find_by_id).with("42") { user }
133
+
134
+ expect(subject.logged_in?).to be true
135
+ end
136
+
137
+ it "logged_in? returns false if not logged in" do
138
+ session[:user_id] = nil
139
+
140
+ expect(subject.logged_in?).to be false
141
+ end
142
+
143
+ it "current_user returns the user instance if logged in" do
144
+ session[:user_id] = user.id.to_s
145
+ expect(User.sorcery_adapter).to receive(:find_by_id).with("42") { user }
146
+
147
+ 2.times { expect(subject.current_user).to eq user } # memoized!
148
+ end
149
+
150
+ it "current_user returns false if not logged in" do
151
+ session[:user_id] = nil
152
+ expect(User.sorcery_adapter).to_not receive(:find_by_id)
153
+
154
+ 2.times { expect(subject.current_user).to be_nil } # memoized!
155
+ end
156
+
157
+ specify { should respond_to(:require_login) }
158
+
159
+ it "calls the configured 'not_authenticated_action' when authenticate before_filter fails" do
160
+ session[:user_id] = nil
161
+ sorcery_controller_property_set(:not_authenticated_action, :test_not_authenticated_action)
162
+ get :test_logout
163
+
164
+ expect(response.body).to eq "test_not_authenticated_action"
165
+ end
166
+
167
+ it "require_login before_filter saves the url that the user originally wanted" do
168
+ get :some_action
169
+
170
+ expect(session[:return_to_url]).to eq "http://test.host/some_action"
171
+ expect(response).to redirect_to("http://test.host/")
172
+ end
173
+
174
+ it "require_login before_filter does not save the url that the user originally wanted upon all non-get http methods" do
175
+ [:post, :put, :delete].each do |m|
176
+ self.send(m, :some_action)
177
+
178
+ expect(session[:return_to_url]).to be_nil
179
+ end
180
+ end
181
+
182
+ it "on successful login the user is redirected to the url he originally wanted" do
183
+ session[:return_to_url] = "http://test.host/some_action"
184
+ post :test_return_to, :email => 'bla@bla.com', :password => 'secret'
185
+
186
+ expect(response).to redirect_to("http://test.host/some_action")
187
+ expect(flash[:notice]).to eq "haha!"
188
+ end
189
+
190
+
191
+ # --- auto_login(user) ---
192
+ specify { should respond_to(:auto_login) }
193
+
194
+ it "auto_login(user) los in a user instance" do
195
+ session[:user_id] = nil
196
+ subject.auto_login(user)
197
+
198
+ expect(subject.logged_in?).to be true
199
+ end
200
+
201
+ it "auto_login(user) works even if current_user was already set to false" do
202
+ get :test_logout
203
+
204
+ expect(session[:user_id]).to be_nil
205
+ expect(subject.current_user).to be_nil
206
+
207
+ expect(User).to receive(:first) { user }
208
+
209
+ get :test_auto_login
210
+
211
+ expect(assigns[:result]).to eq user
212
+ end
213
+ end
214
+
215
+ end