sorcery 0.7.4 → 0.8.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 (70) hide show
  1. data/.travis.yml +3 -0
  2. data/Gemfile +9 -4
  3. data/Gemfile.lock +103 -62
  4. data/README.rdoc +33 -8
  5. data/Rakefile +6 -7
  6. data/VERSION +1 -1
  7. data/lib/generators/sorcery/install_generator.rb +15 -10
  8. data/lib/generators/sorcery/templates/initializer.rb +343 -125
  9. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +2 -0
  10. data/lib/generators/sorcery/templates/migration/reset_password.rb +1 -1
  11. data/lib/sorcery/controller/submodules/activity_logging.rb +3 -3
  12. data/lib/sorcery/controller/submodules/brute_force_protection.rb +1 -2
  13. data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +19 -19
  14. data/lib/sorcery/controller/submodules/external/providers/facebook.rb +20 -5
  15. data/lib/sorcery/controller/submodules/external/providers/github.rb +15 -4
  16. data/lib/sorcery/controller/submodules/external/providers/google.rb +90 -0
  17. data/lib/sorcery/controller/submodules/external/providers/linkedin.rb +101 -0
  18. data/lib/sorcery/controller/submodules/external/providers/liveid.rb +91 -0
  19. data/lib/sorcery/controller/submodules/external/providers/twitter.rb +2 -1
  20. data/lib/sorcery/controller/submodules/external/providers/vkontakte.rb +94 -0
  21. data/lib/sorcery/controller/submodules/external.rb +89 -15
  22. data/lib/sorcery/controller/submodules/http_basic_auth.rb +1 -1
  23. data/lib/sorcery/controller/submodules/remember_me.rb +11 -2
  24. data/lib/sorcery/controller.rb +14 -6
  25. data/lib/sorcery/crypto_providers/bcrypt.rb +1 -0
  26. data/lib/sorcery/model/adapters/active_record.rb +21 -1
  27. data/lib/sorcery/model/adapters/mongo_mapper.rb +22 -15
  28. data/lib/sorcery/model/adapters/mongoid.rb +20 -3
  29. data/lib/sorcery/model/submodules/activity_logging.rb +4 -4
  30. data/lib/sorcery/model/submodules/brute_force_protection.rb +46 -15
  31. data/lib/sorcery/model/submodules/remember_me.rb +4 -6
  32. data/lib/sorcery/model/submodules/reset_password.rb +18 -12
  33. data/lib/sorcery/model/submodules/user_activation.rb +15 -8
  34. data/lib/sorcery/model.rb +57 -43
  35. data/lib/sorcery/railties/tasks.rake +2 -0
  36. data/lib/sorcery.rb +5 -1
  37. data/sorcery.gemspec +33 -21
  38. data/spec/Gemfile +1 -1
  39. data/spec/Gemfile.lock +22 -21
  40. data/spec/README.md +8 -8
  41. data/spec/rails3/Gemfile +3 -3
  42. data/spec/rails3/Gemfile.lock +55 -33
  43. data/spec/rails3/app/controllers/application_controller.rb +85 -2
  44. data/spec/rails3/app/mailers/sorcery_mailer.rb +7 -0
  45. data/spec/rails3/app/views/sorcery_mailer/send_unlock_token_email.text.erb +1 -0
  46. data/spec/rails3/config/environments/in_memory.rb +35 -0
  47. data/spec/rails3/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +2 -0
  48. data/spec/rails3/spec/controller_activity_logging_spec.rb +10 -0
  49. data/spec/rails3/spec/controller_brute_force_protection_spec.rb +23 -1
  50. data/spec/rails3/spec/controller_oauth2_spec.rb +260 -22
  51. data/spec/rails3/spec/controller_oauth_spec.rb +111 -6
  52. data/spec/rails3/spec/controller_spec.rb +37 -2
  53. data/spec/rails3/spec/integration_spec.rb +15 -15
  54. data/spec/rails3/spec/spec_helper.rb +1 -1
  55. data/spec/rails3_mongo_mapper/Gemfile +2 -1
  56. data/spec/rails3_mongo_mapper/Gemfile.lock +40 -42
  57. data/spec/rails3_mongo_mapper/app/controllers/application_controller.rb +14 -0
  58. data/spec/rails3_mongo_mapper/spec/controller_spec.rb +41 -1
  59. data/spec/rails3_mongoid/Gemfile +1 -0
  60. data/spec/rails3_mongoid/Gemfile.lock +30 -27
  61. data/spec/rails3_mongoid/app/controllers/application_controller.rb +19 -0
  62. data/spec/rails3_mongoid/config/mongoid.yml +1 -1
  63. data/spec/rails3_mongoid/spec/controller_activity_logging_spec.rb +18 -11
  64. data/spec/rails3_mongoid/spec/controller_spec.rb +41 -1
  65. data/spec/shared_examples/controller_oauth2_shared_examples.rb +20 -1
  66. data/spec/shared_examples/controller_oauth_shared_examples.rb +18 -0
  67. data/spec/shared_examples/user_activation_shared_examples.rb +71 -41
  68. data/spec/shared_examples/user_reset_password_shared_examples.rb +80 -27
  69. data/spec/sorcery_crypto_providers_spec.rb +14 -1
  70. metadata +74 -46
@@ -1,12 +1,10 @@
1
1
  PATH
2
2
  remote: ../../
3
3
  specs:
4
- sorcery (0.7.2)
4
+ sorcery (0.7.13)
5
5
  bcrypt-ruby (~> 3.0.0)
6
6
  oauth (~> 0.4.4)
7
- oauth (~> 0.4.4)
8
- oauth2 (~> 0.4.1)
9
- oauth2 (~> 0.4.1)
7
+ oauth2 (~> 0.8.0)
10
8
 
11
9
  GEM
12
10
  remote: http://rubygems.org/
@@ -38,20 +36,31 @@ GEM
38
36
  activemodel (= 3.0.3)
39
37
  activesupport (= 3.0.3)
40
38
  activesupport (3.0.3)
41
- addressable (2.2.6)
39
+ addressable (2.2.7)
42
40
  archive-tar-minitar (0.5.2)
43
41
  arel (2.0.10)
44
42
  bcrypt-ruby (3.0.1)
45
43
  builder (2.1.2)
46
- columnize (0.3.4)
44
+ capybara (1.1.2)
45
+ mime-types (>= 1.16)
46
+ nokogiri (>= 1.3.3)
47
+ rack (>= 1.0.0)
48
+ rack-test (>= 0.5.4)
49
+ selenium-webdriver (~> 2.0)
50
+ xpath (~> 0.1.4)
51
+ childprocess (0.3.1)
52
+ ffi (~> 1.0.6)
53
+ columnize (0.3.6)
47
54
  diff-lcs (1.1.3)
48
55
  erubis (2.6.6)
49
56
  abstract (>= 1.0.0)
50
- faraday (0.6.1)
51
- addressable (~> 2.2.4)
52
- multipart-post (~> 1.1.0)
53
- rack (>= 1.1.0, < 2)
57
+ faraday (0.8.4)
58
+ multipart-post (~> 1.1)
59
+ ffi (1.0.11)
60
+ httpauth (0.2.0)
54
61
  i18n (0.6.0)
62
+ jwt (0.1.5)
63
+ multi_json (>= 1.0)
55
64
  launchy (2.0.5)
56
65
  addressable (~> 2.2.6)
57
66
  linecache19 (0.5.12)
@@ -62,14 +71,18 @@ GEM
62
71
  mime-types (~> 1.16)
63
72
  treetop (~> 1.4.8)
64
73
  mime-types (1.17.2)
65
- multi_json (1.0.3)
66
- multipart-post (1.1.3)
67
- oauth (0.4.5)
68
- oauth2 (0.4.1)
69
- faraday (~> 0.6.1)
70
- multi_json (>= 0.0.5)
71
- polyglot (0.3.2)
72
- rack (1.2.4)
74
+ multi_json (1.1.0)
75
+ multipart-post (1.1.5)
76
+ nokogiri (1.5.0)
77
+ oauth (0.4.7)
78
+ oauth2 (0.8.0)
79
+ faraday (~> 0.8)
80
+ httpauth (~> 0.1)
81
+ jwt (~> 0.1.4)
82
+ multi_json (~> 1.0)
83
+ rack (~> 1.2)
84
+ polyglot (0.3.3)
85
+ rack (1.2.5)
73
86
  rack-mount (0.6.14)
74
87
  rack (>= 1.0.0)
75
88
  rack-test (0.5.7)
@@ -88,19 +101,19 @@ GEM
88
101
  rake (>= 0.8.7)
89
102
  thor (~> 0.14.4)
90
103
  rake (0.9.2.2)
91
- rspec (2.5.0)
92
- rspec-core (~> 2.5.0)
93
- rspec-expectations (~> 2.5.0)
94
- rspec-mocks (~> 2.5.0)
95
- rspec-core (2.5.2)
96
- rspec-expectations (2.5.0)
104
+ rspec (2.7.0)
105
+ rspec-core (~> 2.7.0)
106
+ rspec-expectations (~> 2.7.0)
107
+ rspec-mocks (~> 2.7.0)
108
+ rspec-core (2.7.1)
109
+ rspec-expectations (2.7.0)
97
110
  diff-lcs (~> 1.1.2)
98
- rspec-mocks (2.5.0)
99
- rspec-rails (2.5.0)
111
+ rspec-mocks (2.7.0)
112
+ rspec-rails (2.7.0)
100
113
  actionpack (~> 3.0)
101
114
  activesupport (~> 3.0)
102
115
  railties (~> 3.0)
103
- rspec (~> 2.5.0)
116
+ rspec (~> 2.7.0)
104
117
  ruby-debug-base19 (0.11.25)
105
118
  columnize (>= 0.3.1)
106
119
  linecache19 (>= 0.5.11)
@@ -111,11 +124,17 @@ GEM
111
124
  ruby-debug-base19 (>= 0.11.19)
112
125
  ruby_core_source (0.1.5)
113
126
  archive-tar-minitar (>= 0.5.2)
114
- simplecov (0.5.4)
115
- multi_json (~> 1.0.3)
127
+ rubyzip (0.9.6.1)
128
+ selenium-webdriver (2.20.0)
129
+ childprocess (>= 0.2.5)
130
+ ffi (~> 1.0)
131
+ multi_json (~> 1.0)
132
+ rubyzip
133
+ simplecov (0.6.1)
134
+ multi_json (~> 1.0)
116
135
  simplecov-html (~> 0.5.3)
117
136
  simplecov-html (0.5.3)
118
- sqlite3 (1.3.4)
137
+ sqlite3 (1.3.5)
119
138
  sqlite3-ruby (1.3.3)
120
139
  sqlite3 (>= 1.3.3)
121
140
  thor (0.14.6)
@@ -123,16 +142,19 @@ GEM
123
142
  treetop (1.4.10)
124
143
  polyglot
125
144
  polyglot (>= 0.3.1)
126
- tzinfo (0.3.30)
145
+ tzinfo (0.3.31)
146
+ xpath (0.1.4)
147
+ nokogiri (~> 1.3)
127
148
 
128
149
  PLATFORMS
129
150
  ruby
130
151
 
131
152
  DEPENDENCIES
153
+ bcrypt-ruby (~> 3.0.0)
154
+ capybara (~> 1.1.1)
132
155
  launchy (~> 2.0.5)
133
156
  rails (= 3.0.3)
134
- rspec (~> 2.5.0)
135
- rspec-rails (~> 2.5.0)
157
+ rspec-rails (~> 2.7.0)
136
158
  ruby-debug19
137
159
  simplecov (>= 0.3.8)
138
160
  sorcery (>= 0.1.0)!
@@ -9,16 +9,21 @@ class ApplicationController < ActionController::Base
9
9
 
10
10
  def index
11
11
  end
12
-
12
+
13
13
  def some_action
14
14
  render :nothing => true
15
15
  end
16
16
 
17
+ def some_action_making_a_non_persisted_change_to_the_user
18
+ current_user.username = "to_be_ignored"
19
+ render :nothing => true
20
+ end
21
+
17
22
  def test_login
18
23
  @user = login(params[:username], params[:password])
19
24
  render :text => ""
20
25
  end
21
-
26
+
22
27
  def test_auto_login
23
28
  @user = User.find(:first)
24
29
  auto_login(@user)
@@ -84,6 +89,14 @@ class ApplicationController < ActionController::Base
84
89
  login_at(:github)
85
90
  end
86
91
 
92
+ def login_at_test4
93
+ login_at(:google)
94
+ end
95
+
96
+ def login_at_test5
97
+ login_at(:liveid)
98
+ end
99
+
87
100
  def test_login_from
88
101
  if @user = login_from(:twitter)
89
102
  redirect_to "bla", :notice => "Success!"
@@ -108,6 +121,62 @@ class ApplicationController < ActionController::Base
108
121
  end
109
122
  end
110
123
 
124
+ def test_login_from4
125
+ if @user = login_from(:google)
126
+ redirect_to "bla", :notice => "Success!"
127
+ else
128
+ redirect_to "blu", :alert => "Failed!"
129
+ end
130
+ end
131
+
132
+ def test_login_from5
133
+ if @user = login_from(:liveid)
134
+ redirect_to "bla", :notice => "Success!"
135
+ else
136
+ redirect_to "blu", :alert => "Failed!"
137
+ end
138
+ end
139
+
140
+ def test_return_to_with_external
141
+ if @user = login_from(:twitter)
142
+ redirect_back_or_to "bla", :notice => "Success!"
143
+ else
144
+ redirect_to "blu", :alert => "Failed!"
145
+ end
146
+ end
147
+
148
+ def test_return_to_with_external2
149
+ if @user = login_from(:facebook)
150
+ redirect_back_or_to "bla", :notice => "Success!"
151
+ else
152
+ redirect_to "blu", :alert => "Failed!"
153
+ end
154
+ end
155
+
156
+ def test_return_to_with_external3
157
+ if @user = login_from(:github)
158
+ redirect_back_or_to "bla", :notice => "Success!"
159
+ else
160
+ redirect_to "blu", :alert => "Failed!"
161
+ end
162
+ end
163
+
164
+ def test_return_to_with_external4
165
+ if @user = login_from(:google)
166
+ redirect_back_or_to "bla", :notice => "Success!"
167
+ else
168
+ redirect_to "blu", :alert => "Failed!"
169
+ end
170
+ end
171
+
172
+ def test_return_to_with_external5
173
+ if @user = login_from(:liveid)
174
+ redirect_back_or_to "bla", :notice => "Success!"
175
+ else
176
+ redirect_to "blu", :alert => "Failed!"
177
+ end
178
+ end
179
+
111
180
  def test_create_from_provider
112
181
  provider = params[:provider]
113
182
  login_from(provider)
@@ -117,6 +186,20 @@ class ApplicationController < ActionController::Base
117
186
  redirect_to "blu", :alert => "Failed!"
118
187
  end
119
188
  end
189
+
190
+ def test_create_from_provider_with_block
191
+ provider = params[:provider]
192
+ login_from(provider)
193
+ @user = create_from(provider) do |user|
194
+ # check uniqueness of username
195
+ User.where(:username => user.username).empty?
196
+ end
197
+ if @user
198
+ redirect_to "bla", :notice => "Success!"
199
+ else
200
+ redirect_to "blu", :alert => "Failed!"
201
+ end
202
+ end
120
203
 
121
204
  protected
122
205
 
@@ -22,4 +22,11 @@ class SorceryMailer < ActionMailer::Base
22
22
  mail(:to => user.email,
23
23
  :subject => "Your password has been reset")
24
24
  end
25
+
26
+ def send_unlock_token_email(user)
27
+ @user = user
28
+ @url = "http://example.com/unlock/#{user.unlock_token}"
29
+ mail(:to => user.email,
30
+ :subject => "Your account has been locked due to many wrong logins")
31
+ end
25
32
  end
@@ -0,0 +1 @@
1
+ Please visit <% @url %> for unlock your account.
@@ -0,0 +1,35 @@
1
+ AppRoot::Application.configure do
2
+ # Settings specified here will take precedence over those in config/application.rb
3
+
4
+ # The test environment is used exclusively to run your application's
5
+ # test suite. You never need to work with it otherwise. Remember that
6
+ # your test database is "scratch space" for the test suite and is wiped
7
+ # and recreated between test runs. Don't rely on the data there!
8
+ config.cache_classes = true
9
+
10
+ # Log error messages when you accidentally call methods on nil.
11
+ config.whiny_nils = true
12
+
13
+ # Show full error reports and disable caching
14
+ config.consider_all_requests_local = true
15
+ config.action_controller.perform_caching = false
16
+
17
+ # Raise exceptions instead of rendering exception templates
18
+ config.action_dispatch.show_exceptions = false
19
+
20
+ # Disable request forgery protection in test environment
21
+ config.action_controller.allow_forgery_protection = true
22
+
23
+ # Tell Action Mailer not to deliver emails to the real world.
24
+ # The :test delivery method accumulates sent emails in the
25
+ # ActionMailer::Base.deliveries array.
26
+ config.action_mailer.delivery_method = :test
27
+
28
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
29
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
30
+ # like if you have constraints or database-specific column types
31
+ # config.active_record.schema_format = :sql
32
+
33
+ # Print deprecation notices to the stderr
34
+ config.active_support.deprecation = :stderr
35
+ end
@@ -2,9 +2,11 @@ class AddBruteForceProtectionToUsers < ActiveRecord::Migration
2
2
  def self.up
3
3
  add_column :users, :failed_logins_count, :integer, :default => 0
4
4
  add_column :users, :lock_expires_at, :datetime, :default => nil
5
+ add_column :users, :unlock_token, :string, :default => nil
5
6
  end
6
7
 
7
8
  def self.down
9
+ remove_column :users, :unlock_token
8
10
  remove_column :users, :lock_expires_at
9
11
  remove_column :users, :failed_logins_count
10
12
  end
@@ -7,6 +7,9 @@ describe ApplicationController do
7
7
 
8
8
  after(:all) do
9
9
  ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/activity_logging")
10
+ sorcery_controller_property_set(:register_login_time, true)
11
+ sorcery_controller_property_set(:register_logout_time, true)
12
+ sorcery_controller_property_set(:register_last_activity_time, true)
10
13
  end
11
14
 
12
15
  # ----------------- ACTIVITY LOGGING -----------------------
@@ -54,6 +57,13 @@ describe ApplicationController do
54
57
  User.first.last_activity_at.to_s(:db).should <= (now+2).to_s(:db)
55
58
  end
56
59
 
60
+ it "should update nothing but activity fields" do
61
+ original_user_name = User.first.username
62
+ login_user
63
+ get :some_action_making_a_non_persisted_change_to_the_user
64
+ User.first.username.should == original_user_name
65
+ end
66
+
57
67
  it "'current_users' should hold the user object when 1 user is logged in" do
58
68
  login_user
59
69
  get :some_action
@@ -21,12 +21,34 @@ describe ApplicationController do
21
21
  sorcery_controller_property_set(:user_class, User)
22
22
  Timecop.return
23
23
  end
24
-
24
+
25
25
  it "should count login retries" do
26
26
  3.times {get :test_login, :username => 'gizmo', :password => 'blabla'}
27
27
  User.find_by_username('gizmo').failed_logins_count.should == 3
28
28
  end
29
29
 
30
+ it "should generate unlock token after user locked" do
31
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
32
+ sorcery_model_property_set(:login_lock_time_period, 0)
33
+ sorcery_model_property_set(:unlock_token_mailer, SorceryMailer)
34
+ 3.times {get :test_login, :username => "gizmo", :password => "blabla"}
35
+ User.find_by_username('gizmo').unlock_token.should_not be_nil
36
+ end
37
+
38
+ it "should unlock after entering unlock token" do
39
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
40
+ sorcery_model_property_set(:login_lock_time_period, 0)
41
+ sorcery_model_property_set(:unlock_token_mailer, SorceryMailer)
42
+ 3.times {get :test_login, :username => "gizmo", :password => "blabla"}
43
+ User.find_by_username('gizmo').unlock_token.should_not be_nil
44
+ token = User.find_by_username('gizmo').unlock_token
45
+ user = User.load_from_unlock_token(token)
46
+ user.should_not be_nil
47
+ user.unlock!
48
+ User.load_from_unlock_token(token).should be_nil
49
+ end
50
+
51
+
30
52
  it "should reset the counter on a good login" do
31
53
  sorcery_model_property_set(:consecutive_login_retries_amount_limit, 5)
32
54
  3.times {get :test_login, :username => 'gizmo', :password => 'blabla'}