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.
- data/.document +5 -0
- data/.gitignore +56 -0
- data/.rspec +1 -0
- data/.travis.yml +40 -0
- data/CHANGELOG.md +263 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +20 -0
- data/README.md +360 -0
- data/Rakefile +6 -0
- data/gemfiles/active_record-rails40.gemfile +7 -0
- data/gemfiles/active_record-rails41.gemfile +7 -0
- data/lib/generators/sorcery/USAGE +22 -0
- data/lib/generators/sorcery/helpers.rb +40 -0
- data/lib/generators/sorcery/install_generator.rb +95 -0
- data/lib/generators/sorcery/templates/initializer.rb +451 -0
- data/lib/generators/sorcery/templates/migration/activity_logging.rb +10 -0
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +9 -0
- data/lib/generators/sorcery/templates/migration/core.rb +13 -0
- data/lib/generators/sorcery/templates/migration/external.rb +12 -0
- data/lib/generators/sorcery/templates/migration/remember_me.rb +8 -0
- data/lib/generators/sorcery/templates/migration/reset_password.rb +9 -0
- data/lib/generators/sorcery/templates/migration/user_activation.rb +9 -0
- data/lib/sorcery.rb +85 -0
- data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
- data/lib/sorcery/adapters/base_adapter.rb +30 -0
- data/lib/sorcery/controller.rb +157 -0
- data/lib/sorcery/controller/config.rb +65 -0
- data/lib/sorcery/controller/submodules/activity_logging.rb +82 -0
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +38 -0
- data/lib/sorcery/controller/submodules/external.rb +199 -0
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +74 -0
- data/lib/sorcery/controller/submodules/remember_me.rb +81 -0
- data/lib/sorcery/controller/submodules/session_timeout.rb +56 -0
- data/lib/sorcery/crypto_providers/aes256.rb +51 -0
- data/lib/sorcery/crypto_providers/bcrypt.rb +97 -0
- data/lib/sorcery/crypto_providers/common.rb +35 -0
- data/lib/sorcery/crypto_providers/md5.rb +19 -0
- data/lib/sorcery/crypto_providers/sha1.rb +28 -0
- data/lib/sorcery/crypto_providers/sha256.rb +36 -0
- data/lib/sorcery/crypto_providers/sha512.rb +36 -0
- data/lib/sorcery/engine.rb +21 -0
- data/lib/sorcery/model.rb +183 -0
- data/lib/sorcery/model/config.rb +96 -0
- data/lib/sorcery/model/submodules/activity_logging.rb +70 -0
- data/lib/sorcery/model/submodules/brute_force_protection.rb +125 -0
- data/lib/sorcery/model/submodules/external.rb +100 -0
- data/lib/sorcery/model/submodules/remember_me.rb +62 -0
- data/lib/sorcery/model/submodules/reset_password.rb +131 -0
- data/lib/sorcery/model/submodules/user_activation.rb +149 -0
- data/lib/sorcery/model/temporary_token.rb +30 -0
- data/lib/sorcery/protocols/certs/ca-bundle.crt +5182 -0
- data/lib/sorcery/protocols/oauth.rb +42 -0
- data/lib/sorcery/protocols/oauth2.rb +47 -0
- data/lib/sorcery/providers/base.rb +27 -0
- data/lib/sorcery/providers/facebook.rb +63 -0
- data/lib/sorcery/providers/github.rb +51 -0
- data/lib/sorcery/providers/google.rb +51 -0
- data/lib/sorcery/providers/jira.rb +77 -0
- data/lib/sorcery/providers/linkedin.rb +66 -0
- data/lib/sorcery/providers/liveid.rb +53 -0
- data/lib/sorcery/providers/twitter.rb +59 -0
- data/lib/sorcery/providers/vk.rb +63 -0
- data/lib/sorcery/providers/xing.rb +64 -0
- data/lib/sorcery/railties/tasks.rake +6 -0
- data/lib/sorcery/test_helpers/internal.rb +78 -0
- data/lib/sorcery/test_helpers/internal/rails.rb +68 -0
- data/lib/sorcery/test_helpers/rails/controller.rb +21 -0
- data/lib/sorcery/test_helpers/rails/integration.rb +26 -0
- data/lib/sorcery/version.rb +3 -0
- data/sorcery.gemspec +34 -0
- data/spec/active_record/user_activation_spec.rb +18 -0
- data/spec/active_record/user_activity_logging_spec.rb +17 -0
- data/spec/active_record/user_brute_force_protection_spec.rb +16 -0
- data/spec/active_record/user_oauth_spec.rb +16 -0
- data/spec/active_record/user_remember_me_spec.rb +16 -0
- data/spec/active_record/user_reset_password_spec.rb +16 -0
- data/spec/active_record/user_spec.rb +37 -0
- data/spec/controllers/controller_activity_logging_spec.rb +124 -0
- data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
- data/spec/controllers/controller_http_basic_auth_spec.rb +68 -0
- data/spec/controllers/controller_oauth2_spec.rb +407 -0
- data/spec/controllers/controller_oauth_spec.rb +240 -0
- data/spec/controllers/controller_remember_me_spec.rb +117 -0
- data/spec/controllers/controller_session_timeout_spec.rb +80 -0
- data/spec/controllers/controller_spec.rb +215 -0
- data/spec/orm/active_record.rb +21 -0
- data/spec/rails_app/app/active_record/authentication.rb +3 -0
- data/spec/rails_app/app/active_record/user.rb +5 -0
- data/spec/rails_app/app/active_record/user_provider.rb +3 -0
- data/spec/rails_app/app/controllers/sorcery_controller.rb +265 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/mailers/sorcery_mailer.rb +32 -0
- data/spec/rails_app/app/views/application/index.html.erb +17 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_email.html.erb +17 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_email.text.erb +9 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_needed_email.html.erb +17 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_success_email.html.erb +17 -0
- data/spec/rails_app/app/views/sorcery_mailer/activation_success_email.text.erb +9 -0
- data/spec/rails_app/app/views/sorcery_mailer/reset_password_email.html.erb +16 -0
- data/spec/rails_app/app/views/sorcery_mailer/reset_password_email.text.erb +8 -0
- data/spec/rails_app/app/views/sorcery_mailer/send_unlock_token_email.text.erb +1 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +56 -0
- data/spec/rails_app/config/boot.rb +4 -0
- data/spec/rails_app/config/database.yml +22 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/test.rb +37 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/inflections.rb +10 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/initializers/session_store.rb +12 -0
- data/spec/rails_app/config/locales/en.yml +5 -0
- data/spec/rails_app/config/routes.rb +48 -0
- data/spec/rails_app/db/migrate/activation/20101224223622_add_activation_to_users.rb +17 -0
- data/spec/rails_app/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +19 -0
- data/spec/rails_app/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +13 -0
- data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +16 -0
- data/spec/rails_app/db/migrate/external/20101224223628_create_authentications_and_user_providers.rb +22 -0
- data/spec/rails_app/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +15 -0
- data/spec/rails_app/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +13 -0
- data/spec/rails_app/db/schema.rb +23 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/shared_examples/user_activation_shared_examples.rb +242 -0
- data/spec/shared_examples/user_activity_logging_shared_examples.rb +97 -0
- data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +156 -0
- data/spec/shared_examples/user_oauth_shared_examples.rb +36 -0
- data/spec/shared_examples/user_remember_me_shared_examples.rb +57 -0
- data/spec/shared_examples/user_reset_password_shared_examples.rb +263 -0
- data/spec/shared_examples/user_shared_examples.rb +467 -0
- data/spec/sorcery_crypto_providers_spec.rb +198 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +41 -0
- 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
|