sorcery 0.5.0 → 0.6.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.
- data/README.rdoc +9 -1
- data/VERSION +1 -1
- data/lib/sorcery/controller/adapters/sinatra.rb +35 -28
- data/lib/sorcery/controller/submodules/activity_logging.rb +11 -7
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +8 -5
- data/lib/sorcery/controller/submodules/external.rb +11 -6
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +12 -7
- data/lib/sorcery/controller/submodules/remember_me.rb +14 -5
- data/lib/sorcery/controller/submodules/session_timeout.rb +3 -1
- data/lib/sorcery/controller.rb +12 -9
- data/lib/sorcery/crypto_providers/aes256.rb +8 -5
- data/lib/sorcery/crypto_providers/bcrypt.rb +12 -6
- data/lib/sorcery/crypto_providers/sha256.rb +2 -1
- data/lib/sorcery/crypto_providers/sha512.rb +2 -1
- data/lib/sorcery/engine.rb +0 -7
- data/lib/sorcery/initializers/initializer.rb +127 -36
- data/lib/sorcery/model/adapters/active_record.rb +2 -2
- data/lib/sorcery/model/adapters/mongoid.rb +12 -7
- data/lib/sorcery/model/submodules/activity_logging.rb +7 -6
- data/lib/sorcery/model/submodules/brute_force_protection.rb +10 -6
- data/lib/sorcery/model/submodules/external.rb +4 -2
- data/lib/sorcery/model/submodules/remember_me.rb +4 -3
- data/lib/sorcery/model/submodules/reset_password.rb +21 -11
- data/lib/sorcery/model/submodules/user_activation.rb +23 -10
- data/lib/sorcery/model/temporary_token.rb +3 -2
- data/lib/sorcery/model.rb +60 -29
- data/lib/sorcery/test_helpers/internal/rails.rb +6 -1
- data/lib/sorcery/test_helpers/internal/sinatra.rb +3 -3
- data/lib/sorcery/test_helpers/internal/sinatra_modular.rb +74 -0
- data/lib/sorcery/test_helpers/internal.rb +2 -1
- data/lib/sorcery.rb +3 -5
- data/sorcery.gemspec +72 -2
- data/spec/Gemfile.lock +1 -4
- data/spec/rails3/Gemfile.lock +1 -4
- data/spec/rails3/spec/controller_oauth2_spec.rb +3 -24
- data/spec/rails3/spec/controller_oauth_spec.rb +3 -24
- data/spec/rails3/spec/controller_spec.rb +2 -2
- data/spec/rails3/spec/user_activation_spec.rb +2 -168
- data/spec/rails3/spec/user_activity_logging_spec.rb +2 -30
- data/spec/rails3/spec/user_brute_force_protection_spec.rb +2 -35
- data/spec/rails3/spec/user_oauth_spec.rb +2 -26
- data/spec/rails3/spec/user_remember_me_spec.rb +2 -45
- data/spec/rails3/spec/user_reset_password_spec.rb +3 -168
- data/spec/rails3/spec/user_spec.rb +3 -293
- data/spec/rails3_mongoid/Gemfile.lock +1 -4
- data/spec/rails3_mongoid/app/models/authentication.rb +3 -3
- data/spec/rails3_mongoid/spec/user_activation_spec.rb +2 -171
- data/spec/rails3_mongoid/spec/user_activity_logging_spec.rb +2 -25
- data/spec/rails3_mongoid/spec/user_brute_force_protection_spec.rb +2 -35
- data/spec/rails3_mongoid/spec/user_oauth_spec.rb +2 -28
- data/spec/rails3_mongoid/spec/user_remember_me_spec.rb +2 -45
- data/spec/rails3_mongoid/spec/user_reset_password_spec.rb +2 -168
- data/spec/rails3_mongoid/spec/user_spec.rb +3 -295
- data/spec/shared_examples/controller_oauth2_shared_examples.rb +37 -0
- data/spec/shared_examples/controller_oauth_shared_examples.rb +37 -0
- data/spec/shared_examples/user_activation_shared_examples.rb +173 -0
- data/spec/shared_examples/user_activity_logging_shared_examples.rb +27 -0
- data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +37 -0
- data/spec/shared_examples/user_oauth_shared_examples.rb +31 -0
- data/spec/shared_examples/user_remember_me_shared_examples.rb +47 -0
- data/spec/shared_examples/user_reset_password_shared_examples.rb +177 -0
- data/spec/shared_examples/user_shared_examples.rb +292 -0
- data/spec/sinatra/Gemfile +3 -0
- data/spec/sinatra/Gemfile.lock +17 -34
- data/spec/sinatra/Rakefile +1 -1
- data/spec/sinatra/filters.rb +20 -14
- data/spec/sinatra/modular.rb +157 -0
- data/spec/sinatra/spec/controller_oauth2_spec.rb +3 -24
- data/spec/sinatra/spec/controller_oauth_spec.rb +3 -24
- data/spec/sinatra/spec/controller_spec.rb +2 -2
- data/spec/sinatra_modular/Gemfile +15 -0
- data/spec/sinatra_modular/Gemfile.lock +117 -0
- data/spec/sinatra_modular/Rakefile +11 -0
- data/spec/sinatra_modular/authentication.rb +3 -0
- data/spec/sinatra_modular/db/migrate/activation/20101224223622_add_activation_to_users.rb +17 -0
- data/spec/sinatra_modular/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +17 -0
- data/spec/sinatra_modular/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +11 -0
- data/spec/sinatra_modular/db/migrate/core/20101224223620_create_users.rb +16 -0
- data/spec/sinatra_modular/db/migrate/external/20101224223628_create_authentications.rb +14 -0
- data/spec/sinatra_modular/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +15 -0
- data/spec/sinatra_modular/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +13 -0
- data/spec/sinatra_modular/filters.rb +27 -0
- data/spec/sinatra_modular/modular.rb +157 -0
- data/spec/sinatra_modular/myapp.rb +133 -0
- data/spec/sinatra_modular/sorcery_mailer.rb +25 -0
- data/spec/sinatra_modular/spec_modular/controller_activity_logging_spec.rb +85 -0
- data/spec/sinatra_modular/spec_modular/controller_brute_force_protection_spec.rb +70 -0
- data/spec/sinatra_modular/spec_modular/controller_http_basic_auth_spec.rb +53 -0
- data/spec/sinatra_modular/spec_modular/controller_oauth2_spec.rb +99 -0
- data/spec/sinatra_modular/spec_modular/controller_oauth_spec.rb +100 -0
- data/spec/sinatra_modular/spec_modular/controller_remember_me_spec.rb +64 -0
- data/spec/sinatra_modular/spec_modular/controller_session_timeout_spec.rb +57 -0
- data/spec/sinatra_modular/spec_modular/controller_spec.rb +116 -0
- data/spec/sinatra_modular/spec_modular/spec.opts +2 -0
- data/spec/sinatra_modular/spec_modular/spec_helper.rb +51 -0
- data/spec/sinatra_modular/user.rb +6 -0
- data/spec/sinatra_modular/views/test_login.erb +4 -0
- metadata +72 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Modular do
|
|
4
|
+
before(:all) do
|
|
5
|
+
ActiveRecord::Migrator.migrate("#{APP_ROOT}/db/migrate/activity_logging")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
after(:all) do
|
|
9
|
+
ActiveRecord::Migrator.rollback("#{APP_ROOT}/db/migrate/activity_logging")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# ----------------- ACTIVITY LOGGING -----------------------
|
|
13
|
+
describe Modular, "with activity logging features" do
|
|
14
|
+
before(:all) do
|
|
15
|
+
sorcery_reload!([:activity_logging])
|
|
16
|
+
clear_cookies
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
before(:each) do
|
|
20
|
+
create_new_user
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
after(:each) do
|
|
24
|
+
User.delete_all
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should respond to 'current_users'" do
|
|
28
|
+
get_sinatra_app(subject).should respond_to(:current_users)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "'current_users' should be empty when no users are logged in" do
|
|
32
|
+
get_sinatra_app(subject).current_users.size.should == 0
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should log login time on login" do
|
|
36
|
+
now = Time.now.utc
|
|
37
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
38
|
+
User.first.last_login_at.should_not be_nil
|
|
39
|
+
User.first.last_login_at.to_s(:db).should >= now.to_s(:db)
|
|
40
|
+
User.first.last_login_at.to_s(:db).should <= (now+2).to_s(:db)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should log logout time on logout" do
|
|
44
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
45
|
+
now = Time.now.utc
|
|
46
|
+
get "/test_logout"
|
|
47
|
+
User.first.last_logout_at.should_not be_nil
|
|
48
|
+
User.first.last_logout_at.to_s(:db).should >= now.to_s(:db)
|
|
49
|
+
User.first.last_logout_at.to_s(:db).should <= (now+2).to_s(:db)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should log last activity time when logged in" do
|
|
53
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
54
|
+
now = Time.now.utc
|
|
55
|
+
get "/some_action"
|
|
56
|
+
User.first.last_activity_at.to_s.should >= now.to_s(:db)
|
|
57
|
+
User.first.last_activity_at.to_s.should <= (now+2).to_s(:db)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "'current_users' should hold the user object when 1 user is logged in" do
|
|
61
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
62
|
+
get "/some_action"
|
|
63
|
+
get_sinatra_app(subject).current_users.size.should == 1
|
|
64
|
+
get_sinatra_app(subject).current_users[0].should == @user
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "'current_users' should show all current_users, whether they have logged out before or not." do
|
|
68
|
+
user1 = create_new_user({:username => 'gizmo1', :email => "bla1@bla.com", :password => 'secret1'})
|
|
69
|
+
get "/test_login", :username => 'gizmo1', :password => 'secret1'
|
|
70
|
+
get "/some_action"
|
|
71
|
+
clear_user_without_logout
|
|
72
|
+
user2 = create_new_user({:username => 'gizmo2', :email => "bla2@bla.com", :password => 'secret2'})
|
|
73
|
+
get "/test_login", :username => 'gizmo2', :password => 'secret2'
|
|
74
|
+
get "/some_action"
|
|
75
|
+
clear_user_without_logout
|
|
76
|
+
user3 = create_new_user({:username => 'gizmo3', :email => "bla3@bla.com", :password => 'secret3'})
|
|
77
|
+
get "/test_login", :username => 'gizmo3', :password => 'secret3'
|
|
78
|
+
get "/some_action"
|
|
79
|
+
get_sinatra_app(subject).current_users.size.should == 3
|
|
80
|
+
get_sinatra_app(subject).current_users[0].should == user1
|
|
81
|
+
get_sinatra_app(subject).current_users[1].should == user2
|
|
82
|
+
get_sinatra_app(subject).current_users[2].should == user3
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Modular do
|
|
4
|
+
before(:all) do
|
|
5
|
+
ActiveRecord::Migrator.migrate("#{APP_ROOT}/db/migrate/brute_force_protection")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
after(:all) do
|
|
9
|
+
ActiveRecord::Migrator.rollback("#{APP_ROOT}/db/migrate/brute_force_protection")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# ----------------- SESSION TIMEOUT -----------------------
|
|
13
|
+
describe Modular, "with brute force protection features" do
|
|
14
|
+
before(:all) do
|
|
15
|
+
sorcery_reload!([:brute_force_protection])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
before(:each) do
|
|
19
|
+
create_new_user
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
after(:each) do
|
|
23
|
+
Sorcery::Controller::Config.reset!
|
|
24
|
+
sorcery_controller_property_set(:user_class, User)
|
|
25
|
+
User.delete_all
|
|
26
|
+
Timecop.return
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should count login retries" do
|
|
30
|
+
3.times {get "/test_login", :username => 'gizmo', :password => 'blabla'}
|
|
31
|
+
User.find_by_username('gizmo').failed_logins_count.should == 3
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should reset the counter on a good login" do
|
|
35
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 5)
|
|
36
|
+
3.times {get "/test_login", :username => 'gizmo', :password => 'blabla'}
|
|
37
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
38
|
+
User.find_by_username('gizmo').failed_logins_count.should == 0
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should lock user when number of retries reached the limit" do
|
|
42
|
+
User.find_by_username('gizmo').lock_expires_at.should be_nil
|
|
43
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 1)
|
|
44
|
+
get "/test_login", :username => 'gizmo', :password => 'blabla'
|
|
45
|
+
User.find_by_username('gizmo').lock_expires_at.should_not be_nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should unlock after lock time period passes" do
|
|
49
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
|
|
50
|
+
sorcery_model_property_set(:login_lock_time_period, 0.2)
|
|
51
|
+
get "/test_login", :username => 'gizmo', :password => 'blabla'
|
|
52
|
+
get "/test_login", :username => 'gizmo', :password => 'blabla'
|
|
53
|
+
User.find_by_username('gizmo').lock_expires_at.should_not be_nil
|
|
54
|
+
Timecop.travel(Time.now+0.3)
|
|
55
|
+
get "/test_login", :username => 'gizmo', :password => 'blabla'
|
|
56
|
+
User.find_by_username('gizmo').lock_expires_at.should be_nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should not unlock if time period is 0 (permanent lock)" do
|
|
60
|
+
sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
|
|
61
|
+
sorcery_model_property_set(:login_lock_time_period, 0)
|
|
62
|
+
get "/test_login", :username => 'gizmo', :password => 'blabla'
|
|
63
|
+
get "/test_login", :username => 'gizmo', :password => 'blabla'
|
|
64
|
+
unlock_date = User.find_by_username('gizmo').lock_expires_at
|
|
65
|
+
Timecop.travel(Time.now+1)
|
|
66
|
+
get "/test_login", :username => 'gizmo', :password => 'blabla'
|
|
67
|
+
User.find_by_username('gizmo').lock_expires_at.to_s.should == unlock_date.to_s
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
require 'base64'
|
|
3
|
+
|
|
4
|
+
describe Modular do
|
|
5
|
+
|
|
6
|
+
# ----------------- HTTP BASIC AUTH -----------------------
|
|
7
|
+
describe Modular, "with http basic auth features" do
|
|
8
|
+
before(:all) do
|
|
9
|
+
sorcery_reload!([:http_basic_auth])
|
|
10
|
+
create_new_user
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after(:each) do
|
|
14
|
+
get "/test_logout"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "requests basic authentication when before_filter is used" do
|
|
18
|
+
session[:http_authentication_used] = nil
|
|
19
|
+
get "/test_http_basic_auth"
|
|
20
|
+
last_response.status.should == 401
|
|
21
|
+
session[:http_authentication_used].should == true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "authenticates from http basic if credentials are sent" do
|
|
25
|
+
session[:http_authentication_used] = true
|
|
26
|
+
get "/test_http_basic_auth", {}, {"HTTP_AUTHORIZATION" => "Basic " + Base64::encode64("#{@user.username}:secret")}
|
|
27
|
+
last_response.should be_ok
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "fails authentication if credentials are wrong" do
|
|
31
|
+
session[:http_authentication_used] = true
|
|
32
|
+
get "/test_http_basic_auth", {}, {"HTTP_AUTHORIZATION" => "Basic " + Base64::encode64("#{@user.username}:wrong!")}
|
|
33
|
+
last_response.should redirect_to 'http://example.org/'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should allow configuration option 'controller_to_realm_map'" do
|
|
37
|
+
sorcery_controller_property_set(:controller_to_realm_map, {"1" => "2"})
|
|
38
|
+
Sorcery::Controller::Config.controller_to_realm_map.should == {"1" => "2"}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should display the correct realm name configured for the controller" do
|
|
42
|
+
sorcery_controller_property_set(:controller_to_realm_map, {"application" => "Salad"})
|
|
43
|
+
get "/test_http_basic_auth"
|
|
44
|
+
last_response.headers["WWW-Authenticate"].should == "Basic realm=\"Salad\""
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should sign in the user's session on successful login" do
|
|
48
|
+
session[:http_authentication_used] = true
|
|
49
|
+
get "/test_http_basic_auth", {}, {"HTTP_AUTHORIZATION" => "Basic " + Base64::encode64("#{@user.username}:secret")}
|
|
50
|
+
session[:user_id].should == User.find_by_username(@user.username).id
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../shared_examples/controller_oauth2_shared_examples')
|
|
3
|
+
|
|
4
|
+
def stub_all_oauth2_requests!
|
|
5
|
+
@client = OAuth2::Client.new("key","secret", :site => "http://myapi.com")
|
|
6
|
+
OAuth2::Client.stub!(:new).and_return(@client)
|
|
7
|
+
@acc_token = OAuth2::AccessToken.new(@client, "", "asd", nil, {})
|
|
8
|
+
@webby = @client.web_server
|
|
9
|
+
OAuth2::Strategy::WebServer.stub!(:new).and_return(@webby)
|
|
10
|
+
@webby.stub!(:get_access_token).and_return(@acc_token)
|
|
11
|
+
@acc_token.stub!(:get).and_return({"id"=>"123", "name"=>"Noam Ben Ari", "first_name"=>"Noam", "last_name"=>"Ben Ari", "link"=>"http://www.facebook.com/nbenari1", "hometown"=>{"id"=>"110619208966868", "name"=>"Haifa, Israel"}, "location"=>{"id"=>"106906559341067", "name"=>"Pardes Hanah, Hefa, Israel"}, "bio"=>"I'm a new daddy, and enjoying it!", "gender"=>"male", "email"=>"nbenari@gmail.com", "timezone"=>2, "locale"=>"en_US", "languages"=>[{"id"=>"108405449189952", "name"=>"Hebrew"}, {"id"=>"106059522759137", "name"=>"English"}, {"id"=>"112624162082677", "name"=>"Russian"}], "verified"=>true, "updated_time"=>"2011-02-16T20:59:38+0000"}.to_json)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe 'MyApp' do
|
|
15
|
+
before(:all) do
|
|
16
|
+
ActiveRecord::Migrator.migrate("#{APP_ROOT}/db/migrate/external")
|
|
17
|
+
sorcery_reload!([:external])
|
|
18
|
+
sorcery_controller_property_set(:external_providers, [:facebook])
|
|
19
|
+
sorcery_controller_external_property_set(:facebook, :key, "eYVNBjBDi33aa9GkA3w")
|
|
20
|
+
sorcery_controller_external_property_set(:facebook, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
|
21
|
+
sorcery_controller_external_property_set(:facebook, :callback_url, "http://blabla.com")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
after(:all) do
|
|
25
|
+
ActiveRecord::Migrator.rollback("#{APP_ROOT}/db/migrate/external")
|
|
26
|
+
end
|
|
27
|
+
# ----------------- OAuth -----------------------
|
|
28
|
+
describe Modular, "with OAuth features" do
|
|
29
|
+
|
|
30
|
+
before(:each) do
|
|
31
|
+
stub_all_oauth2_requests!
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
after(:each) do
|
|
35
|
+
User.delete_all
|
|
36
|
+
Authentication.delete_all
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "login_at redirects correctly" do
|
|
40
|
+
create_new_user
|
|
41
|
+
get "/login_at_test2"
|
|
42
|
+
last_response.should be_a_redirect
|
|
43
|
+
#last_response.should redirect_to("http://myapi.com/oauth/authorize?client_id=key&redirect_uri=http%3A%2F%2Fblabla.com&scope=email%2Coffline_access&type=web_server")
|
|
44
|
+
last_response.should redirect_to("http://myapi.com/oauth/authorize?client_id=key&redirect_uri=http%3A%2F%2Fblabla.com&scope=email%2Coffline_access&response_type=code")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "'login_from' logins if user exists" do
|
|
48
|
+
sorcery_model_property_set(:authentications_class, Authentication)
|
|
49
|
+
create_new_external_user(:facebook)
|
|
50
|
+
get "/test_login_from2"
|
|
51
|
+
last_response.body.should == "Success!"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "'login_from' fails if user doesn't exist" do
|
|
55
|
+
sorcery_model_property_set(:authentications_class, Authentication)
|
|
56
|
+
create_new_user
|
|
57
|
+
get "/test_login_from2"
|
|
58
|
+
last_response.body.should == "Failed!"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
describe Modular do
|
|
63
|
+
it_behaves_like "oauth2_controller"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe Modular, "OAuth with User Activation features" do
|
|
67
|
+
before(:all) do
|
|
68
|
+
ActiveRecord::Migrator.migrate("#{APP_ROOT}/db/migrate/activation")
|
|
69
|
+
sorcery_reload!([:user_activation,:external], :user_activation_mailer => ::SorceryMailer)
|
|
70
|
+
sorcery_controller_property_set(:external_providers, [:facebook])
|
|
71
|
+
sorcery_controller_external_property_set(:facebook, :key, "eYVNBjBDi33aa9GkA3w")
|
|
72
|
+
sorcery_controller_external_property_set(:facebook, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
|
73
|
+
sorcery_controller_external_property_set(:facebook, :callback_url, "http://blabla.com")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
after(:all) do
|
|
77
|
+
ActiveRecord::Migrator.rollback("#{APP_ROOT}/db/migrate/activation")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
after(:each) do
|
|
81
|
+
User.delete_all
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "should not send activation email to external users" do
|
|
85
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
86
|
+
create_new_external_user(:facebook)
|
|
87
|
+
ActionMailer::Base.deliveries.size.should == old_size
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should not send external users an activation success email" do
|
|
91
|
+
sorcery_model_property_set(:activation_success_email_method_name, nil)
|
|
92
|
+
create_new_external_user(:facebook)
|
|
93
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
94
|
+
@user.activate!
|
|
95
|
+
ActionMailer::Base.deliveries.size.should == old_size
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../shared_examples/controller_oauth_shared_examples')
|
|
3
|
+
require 'ostruct'
|
|
4
|
+
|
|
5
|
+
def stub_all_oauth_requests!
|
|
6
|
+
@consumer = OAuth::Consumer.new("key","secret", :site => "http://myapi.com")
|
|
7
|
+
OAuth::Consumer.stub!(:new).and_return(@consumer)
|
|
8
|
+
@req_token = OAuth::RequestToken.new(@consumer) # OpenStruct.new()
|
|
9
|
+
@consumer.stub!(:get_request_token).and_return(@req_token)
|
|
10
|
+
@acc_token = OAuth::AccessToken.new(@consumer)
|
|
11
|
+
@req_token.stub!(:get_access_token).and_return(@acc_token)
|
|
12
|
+
session[:request_token] = @req_token.token
|
|
13
|
+
session[:request_token_secret] = @req_token.secret
|
|
14
|
+
OAuth::RequestToken.stub!(:new).and_return(@req_token)
|
|
15
|
+
response = OpenStruct.new()
|
|
16
|
+
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
|
|
17
|
+
@acc_token.stub!(:get).and_return(response)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe Modular do
|
|
21
|
+
before(:all) do
|
|
22
|
+
ActiveRecord::Migrator.migrate("#{APP_ROOT}/db/migrate/external")
|
|
23
|
+
sorcery_reload!([:external])
|
|
24
|
+
sorcery_controller_property_set(:external_providers, [:twitter])
|
|
25
|
+
sorcery_controller_external_property_set(:twitter, :key, "eYVNBjBDi33aa9GkA3w")
|
|
26
|
+
sorcery_controller_external_property_set(:twitter, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
|
27
|
+
sorcery_controller_external_property_set(:twitter, :callback_url, "http://blabla.com")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
after(:all) do
|
|
31
|
+
ActiveRecord::Migrator.rollback("#{APP_ROOT}/db/migrate/external")
|
|
32
|
+
end
|
|
33
|
+
# ----------------- OAuth -----------------------
|
|
34
|
+
describe Modular, "'login_from'" do
|
|
35
|
+
|
|
36
|
+
before(:each) do
|
|
37
|
+
stub_all_oauth_requests!
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
after(:each) do
|
|
41
|
+
User.delete_all
|
|
42
|
+
Authentication.delete_all
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "login_at_test redirects correctly" do
|
|
46
|
+
create_new_user
|
|
47
|
+
get "/login_at_test"
|
|
48
|
+
last_response.should be_a_redirect
|
|
49
|
+
last_response.should redirect_to("http://myapi.com/oauth/authorize?oauth_callback=http%3A%2F%2Fblabla.com&oauth_token=")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "logins if user exists" do
|
|
53
|
+
sorcery_model_property_set(:authentications_class, Authentication)
|
|
54
|
+
create_new_external_user(:twitter)
|
|
55
|
+
get '/test_login_from', :oauth_verifier => "blablaRERASDFcxvSDFA"
|
|
56
|
+
last_response.body.should == "Success!"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "'login_from' fails if user doesn't exist" do
|
|
60
|
+
sorcery_model_property_set(:authentications_class, Authentication)
|
|
61
|
+
create_new_user
|
|
62
|
+
get '/test_login_from', :oauth_verifier => "blablaRERASDFcxvSDFA"
|
|
63
|
+
last_response.body.should == "Failed!"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe Modular do
|
|
68
|
+
it_behaves_like "oauth_controller"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe Modular, "OAuth with User Activation features" do
|
|
72
|
+
before(:all) do
|
|
73
|
+
ActiveRecord::Migrator.migrate("#{APP_ROOT}/db/migrate/activation")
|
|
74
|
+
sorcery_reload!([:user_activation,:external], :user_activation_mailer => ::SorceryMailer)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
after(:all) do
|
|
78
|
+
ActiveRecord::Migrator.rollback("#{APP_ROOT}/db/migrate/activation")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
after(:each) do
|
|
82
|
+
User.delete_all
|
|
83
|
+
Authentication.delete_all
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "should not send activation email to external users" do
|
|
87
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
88
|
+
create_new_external_user(:twitter)
|
|
89
|
+
ActionMailer::Base.deliveries.size.should == old_size
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should not send external users an activation success email" do
|
|
93
|
+
sorcery_model_property_set(:activation_success_email_method_name, nil)
|
|
94
|
+
create_new_external_user(:twitter)
|
|
95
|
+
old_size = ActionMailer::Base.deliveries.size
|
|
96
|
+
@user.activate!
|
|
97
|
+
ActionMailer::Base.deliveries.size.should == old_size
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Modular do
|
|
4
|
+
|
|
5
|
+
# ----------------- REMEMBER ME -----------------------
|
|
6
|
+
describe Modular, "with remember me features" do
|
|
7
|
+
before(:all) do
|
|
8
|
+
ActiveRecord::Migrator.migrate("#{APP_ROOT}/db/migrate/remember_me")
|
|
9
|
+
sorcery_reload!([:remember_me])
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
before(:each) do
|
|
13
|
+
create_new_user
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
after(:all) do
|
|
17
|
+
ActiveRecord::Migrator.rollback("#{APP_ROOT}/db/migrate/remember_me")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
after(:each) do
|
|
21
|
+
session = nil
|
|
22
|
+
clear_cookies
|
|
23
|
+
User.delete_all
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should set cookie on remember_me!" do
|
|
27
|
+
post "/test_login_with_remember", :username => 'gizmo', :password => 'secret'
|
|
28
|
+
cookies["remember_me_token"].should == assigns[:user].remember_me_token
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should clear cookie on forget_me!" do
|
|
32
|
+
cookies["remember_me_token"] == {:value => 'asd54234dsfsd43534', :expires => 3600}
|
|
33
|
+
get '/test_logout'
|
|
34
|
+
cookies["remember_me_token"].should == nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "login(username,password,remember_me) should login and remember" do
|
|
38
|
+
post '/test_login_with_remember_in_login', :username => 'gizmo', :password => 'secret', :remember => "1"
|
|
39
|
+
cookies["remember_me_token"].should_not be_nil
|
|
40
|
+
cookies["remember_me_token"].should == assigns[:user].remember_me_token
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "logout should also forget_me!" do
|
|
44
|
+
session[:user_id] = @user.id
|
|
45
|
+
get '/test_logout_with_remember'
|
|
46
|
+
cookies["remember_me_token"].should == nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should login_from_cookie" do
|
|
50
|
+
post "/test_login_with_remember", :username => 'gizmo', :password => 'secret'
|
|
51
|
+
get_sinatra_app(subject).instance_eval do
|
|
52
|
+
@current_user = nil
|
|
53
|
+
end
|
|
54
|
+
session[:user_id] = nil
|
|
55
|
+
get '/test_login_from_cookie'
|
|
56
|
+
assigns[:current_user].should == @user
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should not remember_me! when not asked to" do
|
|
60
|
+
post '/test_login', :username => 'gizmo', :password => 'secret'
|
|
61
|
+
cookies["remember_me_token"].should == nil
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Modular do
|
|
4
|
+
|
|
5
|
+
# ----------------- SESSION TIMEOUT -----------------------
|
|
6
|
+
describe Modular, "with session timeout features" do
|
|
7
|
+
before(:all) do
|
|
8
|
+
sorcery_reload!([:session_timeout])
|
|
9
|
+
sorcery_controller_property_set(:session_timeout,0.5)
|
|
10
|
+
create_new_user
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after(:each) do
|
|
14
|
+
Timecop.return
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should not reset session before session timeout" do
|
|
18
|
+
session[:user_id] = User.first.id
|
|
19
|
+
get "/test_should_be_logged_in"
|
|
20
|
+
last_response.should be_ok
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should reset session after session timeout" do
|
|
24
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
25
|
+
session[:user_id].should_not be_nil
|
|
26
|
+
Timecop.travel(Time.now+0.6)
|
|
27
|
+
get "/test_should_be_logged_in"
|
|
28
|
+
last_response.should be_a_redirect
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "with 'session_timeout_from_last_action'" do
|
|
32
|
+
it "should not logout if there was activity" do
|
|
33
|
+
session[:user_id] = nil
|
|
34
|
+
sorcery_controller_property_set(:session_timeout,2)
|
|
35
|
+
sorcery_controller_property_set(:session_timeout_from_last_action, true)
|
|
36
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
37
|
+
Timecop.travel(Time.now+1)
|
|
38
|
+
get "/test_should_be_logged_in"
|
|
39
|
+
session[:user_id].should_not be_nil
|
|
40
|
+
Timecop.travel(Time.now+1)
|
|
41
|
+
get "/test_should_be_logged_in"
|
|
42
|
+
session[:user_id].should_not be_nil
|
|
43
|
+
last_response.should be_ok
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should logout if there was no activity" do
|
|
47
|
+
sorcery_controller_property_set(:session_timeout,0.5)
|
|
48
|
+
sorcery_controller_property_set(:session_timeout_from_last_action, true)
|
|
49
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
50
|
+
Timecop.travel(Time.now+0.6)
|
|
51
|
+
get "/test_should_be_logged_in"
|
|
52
|
+
session[:user_id].should be_nil
|
|
53
|
+
last_response.should be_a_redirect
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Modular do
|
|
4
|
+
|
|
5
|
+
# ----------------- PLUGIN CONFIGURATION -----------------------
|
|
6
|
+
describe "plugin configuration" do
|
|
7
|
+
before(:all) do
|
|
8
|
+
sorcery_reload!
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
after(:each) do
|
|
12
|
+
Sorcery::Controller::Config.reset!
|
|
13
|
+
sorcery_reload!
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should enable configuration option 'user_class'" do
|
|
17
|
+
sorcery_controller_property_set(:user_class, "TestUser")
|
|
18
|
+
Sorcery::Controller::Config.user_class.should == "TestUser"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should enable configuration option 'not_authenticated_action'" do
|
|
22
|
+
sorcery_controller_property_set(:not_authenticated_action, :my_action)
|
|
23
|
+
Sorcery::Controller::Config.not_authenticated_action.should equal(:my_action)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# ----------------- PLUGIN ACTIVATED -----------------------
|
|
29
|
+
describe Modular, "when activated with sorcery" do
|
|
30
|
+
|
|
31
|
+
before(:all) do
|
|
32
|
+
sorcery_reload!
|
|
33
|
+
User.delete_all
|
|
34
|
+
create_new_user
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should respond to the instance method login" do
|
|
38
|
+
get_sinatra_app(subject).should respond_to(:login)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should respond to the instance method logout" do
|
|
42
|
+
get_sinatra_app(subject).should respond_to(:logout)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should respond to the instance method logged_in?" do
|
|
46
|
+
get_sinatra_app(subject).should respond_to(:logged_in?)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should respond to the instance method current_user" do
|
|
50
|
+
get_sinatra_app(subject).should respond_to(:current_user)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "login(username,password) should return the user when success and set the session with user.id" do
|
|
54
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
55
|
+
assigns[:user].should == @user
|
|
56
|
+
session[:user_id].should == @user.id
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "login(username,password) should return nil and not set the session when failure" do
|
|
60
|
+
get "/test_login", :username => 'gizmo', :password => 'opensesame!'
|
|
61
|
+
assigns[:user].should be_nil
|
|
62
|
+
session[:user_id].should be_nil
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "logout should clear the session" do
|
|
66
|
+
get "/test_logout"
|
|
67
|
+
session[:user_id].should be_nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "logged_in? should return true if logged in" do
|
|
71
|
+
get "/test_login", :username => 'gizmo', :password => 'secret'
|
|
72
|
+
assigns[:logged_in].should be_true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "logged_in? should return false if not logged in" do
|
|
76
|
+
get "/test_login", :username => 'gizmo', :password => 'opensesame!'
|
|
77
|
+
assigns[:logged_in].should be_false
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "current_user should return the user instance if logged in" do
|
|
81
|
+
create_new_user
|
|
82
|
+
get "/test_current_user", :id => @user.id
|
|
83
|
+
assigns[:current_user].should == @user
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "current_user should return false if not logged in" do
|
|
87
|
+
get "/test_logout"
|
|
88
|
+
assigns[:current_user].should == false
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "should respond to 'require_login'" do
|
|
92
|
+
get_sinatra_app(subject).should respond_to(:require_login)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "should call the configured 'not_authenticated_action' when authenticate before_filter fails" do
|
|
96
|
+
sorcery_controller_property_set(:not_authenticated_action, :test_not_authenticated_action)
|
|
97
|
+
get "/test_logout"
|
|
98
|
+
last_response.body.should == "test_not_authenticated_action"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "require_login before_filter should save the url that the user originally wanted" do
|
|
102
|
+
sorcery_controller_property_set(:not_authenticated_action, :not_authenticated2)
|
|
103
|
+
get "/some_action"
|
|
104
|
+
assigns[:session][:return_to_url].should == "http://example.org/some_action"
|
|
105
|
+
last_response.status.should == 302
|
|
106
|
+
last_response.should redirect_to("http://example.org/")
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "on successful login the user should be redirected to the url he originally wanted" do
|
|
110
|
+
post "/test_return_to", :username => 'gizmo', :password => 'secret', :return_to_url => "http://example.org/blabla"
|
|
111
|
+
last_response.should redirect_to("http://example.org/blabla")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|