sorcery 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. data/Gemfile +4 -3
  2. data/Gemfile.lock +16 -13
  3. data/LICENSE.txt +1 -1
  4. data/README.rdoc +53 -36
  5. data/Rakefile +7 -13
  6. data/VERSION +1 -1
  7. data/lib/sorcery/controller/submodules/activity_logging.rb +58 -0
  8. data/lib/sorcery/controller/submodules/brute_force_protection.rb +15 -69
  9. data/lib/sorcery/controller/submodules/http_basic_auth.rb +13 -5
  10. data/lib/sorcery/controller/submodules/oauth/oauth1.rb +25 -0
  11. data/lib/sorcery/controller/submodules/oauth/oauth2.rb +23 -0
  12. data/lib/sorcery/controller/submodules/oauth/providers/facebook.rb +64 -0
  13. data/lib/sorcery/controller/submodules/oauth/providers/twitter.rb +61 -0
  14. data/lib/sorcery/controller/submodules/oauth.rb +95 -0
  15. data/lib/sorcery/controller/submodules/remember_me.rb +14 -5
  16. data/lib/sorcery/controller/submodules/session_timeout.rb +10 -2
  17. data/lib/sorcery/controller.rb +40 -22
  18. data/lib/sorcery/crypto_providers/bcrypt.rb +1 -5
  19. data/lib/sorcery/engine.rb +9 -2
  20. data/lib/sorcery/model/submodules/activity_logging.rb +40 -0
  21. data/lib/sorcery/model/submodules/brute_force_protection.rb +79 -0
  22. data/lib/sorcery/model/submodules/oauth.rb +53 -0
  23. data/lib/sorcery/model/submodules/remember_me.rb +6 -2
  24. data/lib/sorcery/model/submodules/reset_password.rb +96 -0
  25. data/lib/sorcery/model/submodules/user_activation.rb +40 -19
  26. data/lib/sorcery/model/temporary_token.rb +22 -0
  27. data/lib/sorcery/model.rb +10 -3
  28. data/lib/sorcery/test_helpers.rb +84 -0
  29. data/lib/sorcery.rb +16 -1
  30. data/sorcery.gemspec +84 -43
  31. data/spec/Gemfile +3 -2
  32. data/spec/Gemfile.lock +15 -2
  33. data/spec/rails3/app_root/.rspec +1 -0
  34. data/spec/rails3/{Gemfile → app_root/Gemfile} +5 -3
  35. data/spec/rails3/{Gemfile.lock → app_root/Gemfile.lock} +25 -2
  36. data/spec/rails3/app_root/app/controllers/application_controller.rb +44 -3
  37. data/spec/rails3/app_root/app/models/authentication.rb +3 -0
  38. data/spec/rails3/app_root/app/models/user.rb +4 -1
  39. data/spec/rails3/app_root/config/application.rb +1 -3
  40. data/spec/rails3/app_root/config/routes.rb +1 -10
  41. data/spec/rails3/app_root/db/migrate/activation/20101224223622_add_activation_to_users.rb +6 -4
  42. data/spec/rails3/app_root/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +17 -0
  43. data/spec/rails3/app_root/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +11 -0
  44. data/spec/rails3/app_root/db/migrate/core/20101224223620_create_users.rb +4 -4
  45. data/spec/rails3/app_root/db/migrate/oauth/20101224223628_create_authentications.rb +14 -0
  46. data/spec/rails3/app_root/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +13 -0
  47. data/spec/rails3/app_root/spec/controller_activity_logging_spec.rb +84 -0
  48. data/spec/rails3/app_root/spec/controller_brute_force_protection_spec.rb +65 -0
  49. data/spec/rails3/{controller_http_basic_auth_spec.rb → app_root/spec/controller_http_basic_auth_spec.rb} +13 -3
  50. data/spec/rails3/app_root/spec/controller_oauth2_spec.rb +117 -0
  51. data/spec/rails3/app_root/spec/controller_oauth_spec.rb +117 -0
  52. data/spec/rails3/{controller_remember_me_spec.rb → app_root/spec/controller_remember_me_spec.rb} +4 -4
  53. data/spec/rails3/{controller_session_timeout_spec.rb → app_root/spec/controller_session_timeout_spec.rb} +5 -4
  54. data/spec/rails3/{controller_spec.rb → app_root/spec/controller_spec.rb} +23 -16
  55. data/spec/rails3/app_root/spec/spec_helper.orig.rb +27 -0
  56. data/spec/rails3/app_root/spec/spec_helper.rb +61 -0
  57. data/spec/rails3/{user_activation_spec.rb → app_root/spec/user_activation_spec.rb} +60 -20
  58. data/spec/rails3/app_root/spec/user_activity_logging_spec.rb +36 -0
  59. data/spec/rails3/app_root/spec/user_brute_force_protection_spec.rb +76 -0
  60. data/spec/rails3/app_root/spec/user_oauth_spec.rb +39 -0
  61. data/spec/rails3/{user_remember_me_spec.rb → app_root/spec/user_remember_me_spec.rb} +4 -4
  62. data/spec/rails3/app_root/spec/user_reset_password_spec.rb +178 -0
  63. data/spec/rails3/{user_spec.rb → app_root/spec/user_spec.rb} +68 -38
  64. metadata +144 -63
  65. data/features/support/env.rb +0 -13
  66. data/lib/sorcery/model/submodules/password_reset.rb +0 -64
  67. data/spec/rails3/app_root/db/migrate/password_reset/20101224223622_add_password_reset_to_users.rb +0 -9
  68. data/spec/rails3/app_root/test/fixtures/users.yml +0 -9
  69. data/spec/rails3/app_root/test/performance/browsing_test.rb +0 -9
  70. data/spec/rails3/app_root/test/test_helper.rb +0 -13
  71. data/spec/rails3/app_root/test/unit/user_test.rb +0 -8
  72. data/spec/rails3/controller_brute_force_protection_spec.rb +0 -72
  73. data/spec/rails3/spec_helper.rb +0 -115
  74. data/spec/rails3/user_password_reset_spec.rb +0 -76
  75. /data/spec/rails3/{Rakefile → app_root/Rakefile} +0 -0
data/spec/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../../../
3
3
  specs:
4
- sorcery (0.1.3)
4
+ sorcery (0.1.4)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -33,6 +33,7 @@ GEM
33
33
  activemodel (= 3.0.3)
34
34
  activesupport (= 3.0.3)
35
35
  activesupport (3.0.3)
36
+ addressable (2.2.4)
36
37
  archive-tar-minitar (0.5.2)
37
38
  arel (2.0.6)
38
39
  bcrypt-ruby (2.1.3)
@@ -41,6 +42,10 @@ GEM
41
42
  diff-lcs (1.1.2)
42
43
  erubis (2.6.6)
43
44
  abstract (>= 1.0.0)
45
+ faraday (0.5.5)
46
+ addressable (~> 2.2.4)
47
+ multipart-post (~> 1.1.0)
48
+ rack (< 2, >= 1.1.0)
44
49
  i18n (0.5.0)
45
50
  linecache19 (0.5.11)
46
51
  ruby_core_source (>= 0.1.4)
@@ -50,6 +55,12 @@ GEM
50
55
  mime-types (~> 1.16)
51
56
  treetop (~> 1.4.8)
52
57
  mime-types (1.16)
58
+ multi_json (0.0.5)
59
+ multipart-post (1.1.0)
60
+ oauth (0.4.4)
61
+ oauth2 (0.1.1)
62
+ faraday (~> 0.5.0)
63
+ multi_json (~> 0.0.4)
53
64
  polyglot (0.3.1)
54
65
  rack (1.2.1)
55
66
  rack-mount (0.6.13)
@@ -101,8 +112,10 @@ PLATFORMS
101
112
 
102
113
  DEPENDENCIES
103
114
  bcrypt-ruby
115
+ oauth (>= 0.4.4)
116
+ oauth2 (>= 0.1.1)
104
117
  rails (= 3.0.3)
105
118
  rspec
106
119
  ruby-debug19
107
120
  simplecov (>= 0.3.8)
108
- sorcery (= 0.1.3)!
121
+ sorcery (= 0.1.4)!
@@ -0,0 +1 @@
1
+ --colour
@@ -2,12 +2,14 @@ source 'http://rubygems.org'
2
2
 
3
3
  gem 'rails', '3.0.3'
4
4
  gem 'sqlite3-ruby', :require => 'sqlite3'
5
- gem "sorcery", '0.1.3', :path => '../../../'
5
+ gem "sorcery", '0.1.4', :path => '../../../'
6
6
  gem 'bcrypt-ruby', '~> 2.1.4', :require => 'bcrypt'
7
-
8
- group :development do
7
+ gem 'oauth', ">= 0.4.4"
8
+ gem 'oauth2', ">= 0.1.1"
9
+ group :development, :test do
9
10
  gem 'rspec'
10
11
  gem 'rspec-rails'
11
12
  gem 'ruby-debug19'
12
13
  gem 'simplecov', '>= 0.3.8', :require => false # Will install simplecov-html as a dependency
14
+ gem 'spork', '~> 0.9.0.rc'
13
15
  end
@@ -1,7 +1,14 @@
1
1
  PATH
2
2
  remote: ../../../
3
3
  specs:
4
- sorcery (0.1.3)
4
+ sorcery (0.1.4)
5
+ bcrypt-ruby (~> 2.1.4)
6
+ json (>= 1.5.1)
7
+ oauth (>= 0.4.4)
8
+ oauth (>= 0.4.4)
9
+ oauth2 (>= 0.1.1)
10
+ oauth2 (>= 0.1.1)
11
+ rails (>= 3.0.0)
5
12
 
6
13
  GEM
7
14
  remote: http://rubygems.org/
@@ -33,6 +40,7 @@ GEM
33
40
  activemodel (= 3.0.3)
34
41
  activesupport (= 3.0.3)
35
42
  activesupport (3.0.3)
43
+ addressable (2.2.4)
36
44
  archive-tar-minitar (0.5.2)
37
45
  arel (2.0.6)
38
46
  bcrypt-ruby (2.1.4)
@@ -41,7 +49,12 @@ GEM
41
49
  diff-lcs (1.1.2)
42
50
  erubis (2.6.6)
43
51
  abstract (>= 1.0.0)
52
+ faraday (0.5.5)
53
+ addressable (~> 2.2.4)
54
+ multipart-post (~> 1.1.0)
55
+ rack (< 2, >= 1.1.0)
44
56
  i18n (0.5.0)
57
+ json (1.5.1)
45
58
  linecache19 (0.5.11)
46
59
  ruby_core_source (>= 0.1.4)
47
60
  mail (2.2.13)
@@ -50,6 +63,12 @@ GEM
50
63
  mime-types (~> 1.16)
51
64
  treetop (~> 1.4.8)
52
65
  mime-types (1.16)
66
+ multi_json (0.0.5)
67
+ multipart-post (1.1.0)
68
+ oauth (0.4.4)
69
+ oauth2 (0.1.1)
70
+ faraday (~> 0.5.0)
71
+ multi_json (~> 0.0.4)
53
72
  polyglot (0.3.1)
54
73
  rack (1.2.1)
55
74
  rack-mount (0.6.13)
@@ -96,6 +115,7 @@ GEM
96
115
  simplecov (0.3.9)
97
116
  simplecov-html (>= 0.3.7)
98
117
  simplecov-html (0.3.9)
118
+ spork (0.9.0.rc3)
99
119
  sqlite3-ruby (1.3.2)
100
120
  thor (0.14.6)
101
121
  treetop (1.4.9)
@@ -107,10 +127,13 @@ PLATFORMS
107
127
 
108
128
  DEPENDENCIES
109
129
  bcrypt-ruby (~> 2.1.4)
130
+ oauth (>= 0.4.4)
131
+ oauth2 (>= 0.1.1)
110
132
  rails (= 3.0.3)
111
133
  rspec
112
134
  rspec-rails
113
135
  ruby-debug19
114
136
  simplecov (>= 0.3.8)
115
- sorcery (= 0.1.3)!
137
+ sorcery (= 0.1.4)!
138
+ spork (~> 0.9.0.rc)
116
139
  sqlite3-ruby
@@ -1,9 +1,11 @@
1
+ require 'oauth'
2
+
1
3
  class ApplicationController < ActionController::Base
2
4
  protect_from_forgery
3
5
 
4
6
  #before_filter :validate_session, :only => [:test_should_be_logged_in] if defined?(:validate_session)
5
- before_filter :require_user_login_from_http, :only => [:test_http_basic_auth]
6
- before_filter :require_user_login, :only => [:test_logout, :test_should_be_logged_in, :some_action]
7
+ before_filter :require_login_from_http_basic, :only => [:test_http_basic_auth]
8
+ before_filter :require_login, :only => [:test_logout, :test_should_be_logged_in, :some_action]
7
9
 
8
10
  def index
9
11
  render :text => ""
@@ -18,6 +20,11 @@ class ApplicationController < ActionController::Base
18
20
  render :text => ""
19
21
  end
20
22
 
23
+ def test_return_to
24
+ @user = login(params[:username], params[:password])
25
+ return_or_redirect_to(:index, :notice => 'haha!')
26
+ end
27
+
21
28
  def test_logout
22
29
  logout
23
30
  render :text => ""
@@ -43,7 +50,7 @@ class ApplicationController < ActionController::Base
43
50
  end
44
51
 
45
52
  def test_login_from_cookie
46
- @user = logged_in_user
53
+ @user = current_user
47
54
  render :text => ""
48
55
  end
49
56
 
@@ -59,6 +66,40 @@ class ApplicationController < ActionController::Base
59
66
  render :text => "HTTP Basic Auth"
60
67
  end
61
68
 
69
+ def auth_at_provider_test
70
+ auth_at_provider(:twitter)
71
+ end
72
+
73
+ def auth_at_provider_test2
74
+ auth_at_provider(:facebook)
75
+ end
76
+
77
+ def test_login_from_access_token
78
+ if @user = login_from_access_token(:twitter)
79
+ redirect_to "bla", :notice => "Success!"
80
+ else
81
+ redirect_to "blu", :alert => "Failed!"
82
+ end
83
+ end
84
+
85
+ def test_login_from_access_token2
86
+ if @user = login_from_access_token(:facebook)
87
+ redirect_to "bla", :notice => "Success!"
88
+ else
89
+ redirect_to "blu", :alert => "Failed!"
90
+ end
91
+ end
92
+
93
+ def test_create_from_provider
94
+ provider = params[:provider]
95
+ login_from_access_token(provider)
96
+ if @user = create_from_provider!(provider)
97
+ redirect_to "bla", :notice => "Success!"
98
+ else
99
+ redirect_to "blu", :alert => "Failed!"
100
+ end
101
+ end
102
+
62
103
  protected
63
104
 
64
105
 
@@ -0,0 +1,3 @@
1
+ class Authentication < ActiveRecord::Base
2
+ belongs_to :user
3
+ end
@@ -1,3 +1,6 @@
1
1
  class User < ActiveRecord::Base
2
- #activate_sorcery!
2
+ attr_accessible :email, :password, :password_confirmation, :authentications_attributes
3
+
4
+ has_many :authentications, :dependent => :destroy
5
+ accepts_nested_attributes_for :authentications
3
6
  end
@@ -38,9 +38,7 @@ module AppRoot
38
38
 
39
39
  # Configure sensitive parameters which will be filtered from the log file.
40
40
  config.filter_parameters += [:password]
41
-
42
- config.root = File.expand_path('../..', __FILE__)
43
-
41
+
44
42
  config.action_mailer.delivery_method = :test
45
43
 
46
44
  config.active_support.deprecation = :stderr
@@ -1,14 +1,5 @@
1
1
  AppRoot::Application.routes.draw do
2
2
  root :to => "application#index"
3
- match '/test_login', :to => "application#test_login"
4
- match '/test_logout', :to => "application#test_logout"
5
- match '/some_action', :to => "application#some_action"
6
- match '/test_logout_with_remember', :to => "application#test_logout_with_remember"
7
- match '/test_login_with_remember', :to => 'application#test_login_with_remember'
8
- match '/test_login_with_remember_in_login', :to => 'application#test_login_with_remember_in_login'
9
- match '/test_login_from_cookie', :to => 'application#test_login_from_cookie'
10
- match '/test_should_be_logged_in', :to => 'application#test_should_be_logged_in'
11
- match '/test_http_basic_auth', :to => 'application#test_http_basic_auth'
12
3
  # The priority is based upon order of creation:
13
4
  # first created -> highest priority.
14
5
 
@@ -64,5 +55,5 @@ AppRoot::Application.routes.draw do
64
55
 
65
56
  # This is a legacy wild controller route that's not recommended for RESTful applications.
66
57
  # Note: This route will make all actions in every controller accessible via GET requests.
67
- # match ':controller(/:action(/:id(.:format)))'
58
+ match ':controller(/:action(/:id(.:format)))'
68
59
  end
@@ -1,15 +1,17 @@
1
1
  class AddActivationToUsers < ActiveRecord::Migration
2
2
  def self.up
3
3
  add_column :users, :activation_state, :string, :default => nil
4
- add_column :users, :activation_code, :string, :default => nil
4
+ add_column :users, :activation_token, :string, :default => nil
5
+ add_column :users, :activation_token_expires_at, :datetime, :default => nil
5
6
 
6
- add_index :users, :activation_code
7
+ add_index :users, :activation_token
7
8
  end
8
9
 
9
10
  def self.down
10
- remove_index :users, :activation_code
11
+ remove_index :users, :activation_token
11
12
 
12
- remove_column :users, :activation_code
13
+ remove_column :users, :activation_token_expires_at
14
+ remove_column :users, :activation_token
13
15
  remove_column :users, :activation_state
14
16
  end
15
17
  end
@@ -0,0 +1,17 @@
1
+ class AddActivityLoggingToUsers < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :users, :last_login_at, :datetime, :default => nil
4
+ add_column :users, :last_logout_at, :datetime, :default => nil
5
+ add_column :users, :last_activity_at, :datetime, :default => nil
6
+
7
+ add_index :users, [:last_logout_at, :last_activity_at]
8
+ end
9
+
10
+ def self.down
11
+ remove_index :users, [:last_logout_at, :last_activity_at]
12
+
13
+ remove_column :users, :last_activity_at
14
+ remove_column :users, :last_logout_at
15
+ remove_column :users, :last_login_at
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ class AddBruteForceProtectionToUsers < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :users, :failed_logins_count, :integer, :default => 0
4
+ add_column :users, :lock_expires_at, :datetime, :default => nil
5
+ end
6
+
7
+ def self.down
8
+ remove_column :users, :lock_expires_at
9
+ remove_column :users, :failed_logins_count
10
+ end
11
+ end
@@ -1,10 +1,10 @@
1
1
  class CreateUsers < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :users do |t|
4
- t.string :username
5
- t.string :email, :null => false
6
- t.string :crypted_password
7
- t.string :salt
4
+ t.string :username, :null => false
5
+ t.string :email, :default => nil
6
+ t.string :crypted_password, :default => nil
7
+ t.string :salt, :default => nil
8
8
 
9
9
  t.timestamps
10
10
  end
@@ -0,0 +1,14 @@
1
+ class CreateAuthentications < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :authentications do |t|
4
+ t.integer :user_id, :null => false
5
+ t.string :provider, :uid, :null => false
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :authentications
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ class AddResetPasswordToUsers < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :users, :reset_password_token, :string, :default => nil
4
+ add_column :users, :reset_password_token_expires_at, :datetime, :default => nil
5
+ add_column :users, :reset_password_email_sent_at, :datetime, :default => nil
6
+ end
7
+
8
+ def self.down
9
+ remove_column :users, :reset_password_email_sent_at
10
+ remove_column :users, :reset_password_token_expires_at
11
+ remove_column :users, :reset_password_token
12
+ end
13
+ end
@@ -0,0 +1,84 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe ApplicationController do
4
+ before(:all) do
5
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/activity_logging")
6
+ end
7
+
8
+ after(:all) do
9
+ ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/activity_logging")
10
+ end
11
+
12
+ # ----------------- ACTIVITY LOGGING -----------------------
13
+ describe ApplicationController, "with activity logging features" do
14
+ before(:all) do
15
+ sorcery_reload!([:activity_logging])
16
+ end
17
+
18
+ before(:each) do
19
+ create_new_user
20
+ end
21
+
22
+ after(:each) do
23
+ User.delete_all
24
+ end
25
+
26
+ it "should respond to 'current_users'" do
27
+ subject.should respond_to(:current_users)
28
+ end
29
+
30
+ it "'current_users' should be empty when no users are logged in" do
31
+ subject.current_users.size.should == 0
32
+ end
33
+
34
+ it "should log login time on login" do
35
+ now = Time.now.utc
36
+ login_user
37
+ @user.last_login_at.should_not be_nil
38
+ @user.last_login_at.to_s(:db).should >= now.to_s(:db)
39
+ @user.last_login_at.to_s(:db).should <= (now+2).to_s(:db)
40
+ end
41
+
42
+ it "should log logout time on logout" do
43
+ login_user
44
+ now = Time.now.utc
45
+ logout_user
46
+ User.first.last_logout_at.should_not be_nil
47
+ User.first.last_logout_at.to_s(:db).should >= now.to_s(:db)
48
+ User.first.last_logout_at.to_s(:db).should <= (now+2).to_s(:db)
49
+ end
50
+
51
+ it "should log last activity time when logged in" do
52
+ login_user
53
+ now = Time.now.utc
54
+ get :some_action
55
+ User.first.last_activity_at.to_s(:db).should >= now.to_s(:db)
56
+ User.first.last_activity_at.to_s(:db).should <= (now+2).to_s(:db)
57
+ end
58
+
59
+ it "'current_users' should hold the user object when 1 user is logged in" do
60
+ login_user
61
+ get :some_action
62
+ subject.current_users.size.should == 1
63
+ subject.current_users[0].should == @user
64
+ end
65
+
66
+ it "'current_users' should show all current_users, whether they have logged out before or not." do
67
+ user1 = create_new_user({:username => 'gizmo1', :email => "bla1@bla.com", :password => 'secret1'})
68
+ login_user(user1)
69
+ get :some_action
70
+ clear_user_without_logout
71
+ user2 = create_new_user({:username => 'gizmo2', :email => "bla2@bla.com", :password => 'secret2'})
72
+ login_user(user2)
73
+ get :some_action
74
+ clear_user_without_logout
75
+ user3 = create_new_user({:username => 'gizmo3', :email => "bla3@bla.com", :password => 'secret3'})
76
+ login_user(user3)
77
+ get :some_action
78
+ subject.current_users.size.should == 3
79
+ subject.current_users[0].should == user1
80
+ subject.current_users[1].should == user2
81
+ subject.current_users[2].should == user3
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,65 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe ApplicationController do
4
+ before(:all) do
5
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/brute_force_protection")
6
+ end
7
+
8
+ after(:all) do
9
+ ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/brute_force_protection")
10
+ end
11
+
12
+ # ----------------- SESSION TIMEOUT -----------------------
13
+ describe ApplicationController, "with brute force protection features" do
14
+ before(:all) do
15
+ sorcery_reload!([:brute_force_protection])
16
+ create_new_user
17
+ end
18
+
19
+ after(:each) do
20
+ Sorcery::Controller::Config.reset!
21
+ sorcery_controller_property_set(:user_class, User)
22
+ end
23
+
24
+ it "should count login retries" do
25
+ 3.times {get :test_login, :username => 'gizmo', :password => 'blabla'}
26
+ User.find_by_username('gizmo').failed_logins_count.should == 3
27
+ end
28
+
29
+ it "should reset the counter on a good login" do
30
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 5)
31
+ 3.times {get :test_login, :username => 'gizmo', :password => 'blabla'}
32
+ get :test_login, :username => 'gizmo', :password => 'secret'
33
+ User.find_by_username('gizmo').failed_logins_count.should == 0
34
+ end
35
+
36
+ it "should lock user when number of retries reached the limit" do
37
+ User.find_by_username('gizmo').lock_expires_at.should be_nil
38
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 1)
39
+ get :test_login, :username => 'gizmo', :password => 'blabla'
40
+ User.find_by_username('gizmo').lock_expires_at.should_not be_nil
41
+ end
42
+
43
+ it "should unlock after lock time period passes" do
44
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
45
+ sorcery_model_property_set(:login_lock_time_period, 0.2)
46
+ get :test_login, :username => 'gizmo', :password => 'blabla'
47
+ get :test_login, :username => 'gizmo', :password => 'blabla'
48
+ User.find_by_username('gizmo').lock_expires_at.should_not be_nil
49
+ sleep 0.3
50
+ get :test_login, :username => 'gizmo', :password => 'blabla'
51
+ User.find_by_username('gizmo').lock_expires_at.should be_nil
52
+ end
53
+
54
+ it "should not unlock if time period is 0 (permanent lock)" do
55
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
56
+ sorcery_model_property_set(:login_lock_time_period, 0)
57
+ get :test_login, :username => 'gizmo', :password => 'blabla'
58
+ get :test_login, :username => 'gizmo', :password => 'blabla'
59
+ unlock_date = User.find_by_username('gizmo').lock_expires_at
60
+ sleep 1
61
+ get :test_login, :username => 'gizmo', :password => 'blabla'
62
+ User.find_by_username('gizmo').lock_expires_at.to_s.should == unlock_date.to_s
63
+ end
64
+ end
65
+ end
@@ -5,10 +5,14 @@ describe ApplicationController do
5
5
  # ----------------- HTTP BASIC AUTH -----------------------
6
6
  describe ApplicationController, "with http basic auth features" do
7
7
  before(:all) do
8
- plugin_model_configure([:http_basic_auth])
8
+ sorcery_reload!([:http_basic_auth])
9
9
  create_new_user
10
10
  end
11
11
 
12
+ after(:each) do
13
+ logout_user
14
+ end
15
+
12
16
  it "requests basic authentication when before_filter is used" do
13
17
  get :test_http_basic_auth
14
18
  response.code.should == "401"
@@ -27,14 +31,20 @@ describe ApplicationController do
27
31
  end
28
32
 
29
33
  it "should allow configuration option 'controller_to_realm_map'" do
30
- plugin_set_controller_config_property(:controller_to_realm_map, {"1" => "2"})
34
+ sorcery_controller_property_set(:controller_to_realm_map, {"1" => "2"})
31
35
  Sorcery::Controller::Config.controller_to_realm_map.should == {"1" => "2"}
32
36
  end
33
37
 
34
38
  it "should display the correct realm name configured for the controller" do
35
- plugin_set_controller_config_property(:controller_to_realm_map, {"application" => "Salad"})
39
+ sorcery_controller_property_set(:controller_to_realm_map, {"application" => "Salad"})
36
40
  get :test_http_basic_auth
37
41
  response.headers["WWW-Authenticate"].should == "Basic realm=\"Salad\""
38
42
  end
43
+
44
+ it "should sign in the user's session on successful login" do
45
+ @request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("#{@user.username}:secret")
46
+ get :test_http_basic_auth, nil, :http_authentication_used => true
47
+ session[:user_id].should == User.find_by_username(@user.username).id
48
+ end
39
49
  end
40
50
  end
@@ -0,0 +1,117 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ def stub_all_oauth2_requests!
4
+ @client = OAuth2::Client.new("key","secret", :site => "http://myapi.com")
5
+ OAuth2::Client.stub!(:new).and_return(@client)
6
+ @acc_token = OAuth2::AccessToken.new(@client, "", "asd", nil, {})
7
+ @webby = @client.web_server
8
+ OAuth2::Strategy::WebServer.stub!(:new).and_return(@webby)
9
+ @webby.stub!(:get_access_token).and_return(@acc_token)
10
+ @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)
11
+ end
12
+
13
+ describe ApplicationController do
14
+ before(:all) do
15
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/oauth")
16
+ sorcery_reload!([:oauth])
17
+ sorcery_controller_property_set(:oauth_providers, [:facebook])
18
+ sorcery_controller_oauth_property_set(:facebook, :key, "eYVNBjBDi33aa9GkA3w")
19
+ sorcery_controller_oauth_property_set(:facebook, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
20
+ sorcery_controller_oauth_property_set(:facebook, :callback_url, "http://blabla.com")
21
+ end
22
+
23
+ after(:all) do
24
+ ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/oauth")
25
+ end
26
+ # ----------------- OAuth -----------------------
27
+ describe ApplicationController, "with OAuth features" do
28
+
29
+ before(:each) do
30
+ stub_all_oauth2_requests!
31
+ end
32
+
33
+ after(:each) do
34
+ User.delete_all
35
+ end
36
+
37
+ it "auth_at_provider redirects correctly" do
38
+ create_new_user
39
+ get :auth_at_provider_test2
40
+ response.should be_a_redirect
41
+ 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")
42
+ end
43
+
44
+ it "'login_from_access_token' logins if user exists" do
45
+ sorcery_model_property_set(:authentications_class, Authentication)
46
+ create_new_external_user(:facebook)
47
+ get :test_login_from_access_token2
48
+ flash[:notice].should == "Success!"
49
+ end
50
+
51
+ it "'login_from_access_token' fails if user doesn't exist" do
52
+ sorcery_model_property_set(:authentications_class, Authentication)
53
+ create_new_user
54
+ get :test_login_from_access_token2
55
+ flash[:alert].should == "Failed!"
56
+ end
57
+ end
58
+
59
+ describe ApplicationController, "'create_from_provider!'" do
60
+ before(:each) do
61
+ stub_all_oauth2_requests!
62
+ User.delete_all
63
+ end
64
+
65
+ it "should create a new user" do
66
+ sorcery_controller_property_set(:authentications_class, Authentication)
67
+ sorcery_controller_oauth_property_set(:facebook, :user_info_mapping, {:username => "name"})
68
+ lambda do
69
+ get :test_create_from_provider, :provider => "facebook"
70
+ end.should change(User, :count).by(1)
71
+ User.first.username.should == "Noam Ben Ari"
72
+ end
73
+
74
+ it "should support nested attributes" do
75
+ sorcery_controller_property_set(:authentications_class, Authentication)
76
+ sorcery_controller_oauth_property_set(:facebook, :user_info_mapping, {:username => "hometown/name"})
77
+ lambda do
78
+ get :test_create_from_provider, :provider => "facebook"
79
+ end.should change(User, :count).by(1)
80
+ User.first.username.should == "Haifa, Israel"
81
+ end
82
+ end
83
+
84
+ describe ApplicationController, "OAuth with User Activation features" do
85
+ before(:all) do
86
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/activation")
87
+ sorcery_reload!([:user_activation,:oauth], :user_activation_mailer => ::SorceryMailer)
88
+ sorcery_controller_property_set(:oauth_providers, [:facebook])
89
+ sorcery_controller_oauth_property_set(:facebook, :key, "eYVNBjBDi33aa9GkA3w")
90
+ sorcery_controller_oauth_property_set(:facebook, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
91
+ sorcery_controller_oauth_property_set(:facebook, :callback_url, "http://blabla.com")
92
+ end
93
+
94
+ after(:all) do
95
+ ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/activation")
96
+ end
97
+
98
+ after(:each) do
99
+ User.delete_all
100
+ end
101
+
102
+ it "should not send activation email to external users" do
103
+ old_size = ActionMailer::Base.deliveries.size
104
+ create_new_external_user(:facebook)
105
+ ActionMailer::Base.deliveries.size.should == old_size
106
+ end
107
+
108
+ it "should not send external users an activation success email" do
109
+ sorcery_model_property_set(:activation_success_email_method_name, nil)
110
+ create_new_external_user(:facebook)
111
+ old_size = ActionMailer::Base.deliveries.size
112
+ @user.activate!
113
+ ActionMailer::Base.deliveries.size.should == old_size
114
+ end
115
+ end
116
+
117
+ end