thoughtbot-clearance 0.4.8 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.textile CHANGED
@@ -1,32 +1,43 @@
1
+ h2. 0.4.9 (2/20/2009)
2
+
3
+ * Protect passwords & confirmations actions with forbidden filters. (Dan Croak)
4
+ * Return 403 Forbidden status code in those cases. (Tim Pope)
5
+ * Test 403 Forbidden status code in Cucumber feature. (Dan Croak, Joe Ferris)
6
+ * Raise custom ActionController::Forbidden error internally. (Joe Ferris, Mike Burns, Jason Morrison)
7
+ * Test ActionController::Forbidden error is raised in functional test. (Joe Ferris, Mike Burns, Dan Croak)
8
+ * [#45] Fixed bug that allowed anyone to edit another user's password (Marcel Görner)
9
+ * Required Factory Girl >= 1.2.0. (Dan Croak)
10
+
1
11
  h2. 0.4.8 (2/16/2009)
2
12
 
3
- * adding support paths for Cucumber (bmabey)
4
- * adding documentation for the flash (bmabey)
5
- * generators require "test_helper" instead of File.join. for rr compatibility. (Joe Ferris)
6
- * removed interpolated email address from flash message to make i18n easier.
7
- * standardized flash messages that refer to email delivery.
13
+ * Added support paths for Cucumber. (Ben Mabey)
14
+ * Added documentation for the flash. (Ben Mabey)
15
+ * Generators require "test_helper" instead of File.join. for rr compatibility. (Joe Ferris)
16
+ * Removed interpolated email address from flash message to make i18n easier. (Bence Nagy)
17
+ * Standardized flash messages that refer to email delivery. (Dan Croak)
8
18
 
9
19
  h2. 0.4.7 (2/12/2009)
10
20
 
11
- * removed Clearance::Test::TestHelper. one less setup step. all test helpers now in shoulda_macros.
21
+ * Removed Clearance::Test::TestHelper so there is one less setup step. (Dan Croak)
22
+ * All test helpers now in shoulda_macros. (Dan Croak)
12
23
 
13
24
  h2. 0.4.6 (2/11/2009)
14
25
 
15
- * making the modules behave like mixins again. (hat-tip Eloy Duran)
16
- * created Actions and PrivateMethods modules on controllers for future RDoc reasons.
26
+ * Made the modules behave like mixins again. (hat-tip Eloy Duran)
27
+ * Created Actions and PrivateMethods modules on controllers for future RDoc reasons. (Dan Croak, Joe Ferris)
17
28
 
18
29
  h2. 0.4.5 (2/9/2009)
19
30
 
20
- * [#43] Removed email downcasing. (local-part is case sensitive per RFC5321)
21
- * [#42] Removed dependency on Mocha.
22
- * Required Shoulda >= 2.9.1.
23
- * Added password reset feature to clearance_features generator.
24
- * Removed unnecessary session[:salt].
25
- * [#41] Only store location for session[:return_to] for GET requests.
26
- * Audited "sign up" naming convention. "Register" had slipped in a few places.
27
- * Switched to SHA1 encryption. Cypher doesn't matter much for email confirmation, password reset. Better to have shorter hashes in the emails for clients who line break on 72 chars.
31
+ * [#43] Removed email downcasing because local-part is case sensitive per RFC5321. (Dan Croak)
32
+ * [#42] Removed dependency on Mocha. (Dan Croak)
33
+ * Required Shoulda >= 2.9.1. (Dan Croak)
34
+ * Added password reset feature to clearance_features generator. (Eugene Bolshakov, Dan Croak)
35
+ * Removed unnecessary session[:salt]. (Dan Croak)
36
+ * [#41] Only store location for session[:return_to] for GET requests. (Dan Croak)
37
+ * Audited "sign up" naming convention. "Register" had slipped in a few places. (Dan Croak)
38
+ * Switched to SHA1 encryption. Cypher doesn't matter much for email confirmation, password reset. Better to have shorter hashes in the emails for clients who line break on 72 chars. (Dan Croak)
28
39
 
29
40
  h2. 0.4.4 (2/2/2009)
30
41
 
31
- * Added a generator for Cucumber features
32
- * Standarized naming for "Sign up," "Sign in," and "Sign out"
42
+ * Added a generator for Cucumber features. (Joe Ferris, Dan Croak)
43
+ * Standarized naming for "Sign up," "Sign in," and "Sign out". (Dan Croak)
data/README.textile CHANGED
@@ -15,7 +15,7 @@ In config/environment.rb:
15
15
  config.gem "thoughtbot-clearance",
16
16
  :lib => 'clearance',
17
17
  :source => 'http://gems.github.com',
18
- :version => '>= 0.4.8'
18
+ :version => '>= 0.4.9'
19
19
 
20
20
  In config/environments/test.rb:
21
21
 
@@ -26,7 +26,7 @@ In config/environments/test.rb:
26
26
  config.gem 'thoughtbot-factory_girl',
27
27
  :lib => 'factory_girl',
28
28
  :source => "http://gems.github.com",
29
- :version => '>= 1.1.5'
29
+ :version => '>= 1.2.0'
30
30
 
31
31
  Then:
32
32
 
@@ -81,7 +81,7 @@ Clearance will add these routes to your routes.rb:
81
81
 
82
82
  Please note that Clearance depends on root_url, so please make sure that it is defined to *something* in your config/routes.rb:
83
83
 
84
- map.root :controller => 'home'
84
+ map.root :controller => 'users', :action => 'new'
85
85
 
86
86
  h2. Environments
87
87
 
@@ -99,11 +99,11 @@ h2. The flash
99
99
 
100
100
  You will need to display the success, failure, and notice flash messages in your layout. We recommend creating an app/layouts/_flashes.html.erb partial similar to the _flashes partial in Suspenders:
101
101
 
102
- <div id="flash">
103
- <% flash.each do |key, value| -%>
104
- <div id="flash_<%= key -%>"><%= html_escape(value) %></div>
105
- <% end -%>
106
- </div>
102
+ <pre><code><div id="flash">
103
+ <% flash.each do |key, value| -%>
104
+ <div id="flash_<%= key -%>"><%= html_escape(value) %></div>
105
+ <% end -%>
106
+ </div></code></pre>
107
107
 
108
108
  which is then rendered inside the body tag of your application layout:
109
109
 
@@ -140,7 +140,7 @@ h2. Usage: basic workflow
140
140
 
141
141
  Rails authentication with Clearance uses the standard approach thoughtbot and our clients have agreed upon.
142
142
 
143
- Users sign up (UsersController) using an email address and a password (User model). They get an email (ClearanceMailer) with a confirmation link to confirm their registration (ConfirmationController).
143
+ Users sign up (UsersController) using an email address and a password (User model). They get an email (ClearanceMailer) with a confirmation link to confirm sign up (ConfirmationController).
144
144
 
145
145
  Signed up and email confirmed users can sign in and out (SessionsController). If they forget their password, they request an email (ClearanceMailer) containing a link to change it (PasswordsController).
146
146
 
@@ -179,6 +179,15 @@ Please note that all User attributes except email, password and password_confirm
179
179
  attr_accessible :first_name, :last_name
180
180
  end
181
181
 
182
+ h2. Usage: when bad things happen to good users
183
+
184
+ Clearance is HTTP fluent. If someone tries to hack the URLs for passwords or confirmations actions, they will be met with a 403 Forbidden HTTP status code. Internally, the Rails app will raise a ApplicationController::Forbidden error. This is a custom error in Clearance.
185
+
186
+ Layman's 403 Forbidden definition:
187
+
188
+ "The request was a legal request, but the server is refusing to respond to it.
189
+ Unlike a 401 Unauthorized response, authenticating will make no difference."
190
+
182
191
  h2. Hooks: return_to parameter
183
192
 
184
193
  To specify where to redirect a user (say you want to have a sign in form on every page and redirect the user to the same page) after he/she signs in, you can add a "return_to" parameter to the request (thanks to "Phillippe":http://www.sivarg.com/2009/01/clearance-coming-from-where-your-were.html for the tip):
@@ -230,21 +239,17 @@ h2. Write your own tests with Clearance's helpers
230
239
 
231
240
  sign_in_as, sign_out, should_be_signed_in_as, should_not_be_signed_in, should_deny_access, signed_in_user_context, and more helpers are available in your test suite. Look in vendor/gems/clearance/shoulda_macros for the full list.
232
241
 
233
- context "when signed in on GET to new" do
234
- setup do
235
- @user = Factory(:email_confirmed_user)
236
- sign_in_as @user
237
- get :new
238
- end
239
- should_be_signed_in_as { @user }
240
- end
242
+ <pre></code>context "when signed in on GET to new" do
243
+ setup do
244
+ @user = Factory(:email_confirmed_user)
245
+ sign_in_as @user
246
+ get :new
247
+ end
248
+ should_be_signed_in_as { @user }
249
+ end</code></pre>
241
250
 
242
251
  h2. Authors
243
252
 
244
- * thoughtbot, inc.
245
- * Dan Croak
246
- * Mike Burns
247
- * Jason Morrison
248
- * Eugene Bolshakov
249
- * Josh Nichols
250
- * Mike Breen
253
+ Clearance was extracted out of "Hoptoad":http://hoptoadapp.com. We merged the authentication code from two of thoughtbot's client's Rails apps. The following people have made significant contributions, suggestions, and generally improved the library. Thank you!
254
+
255
+ Dan Croak, Mike Burns, Jason Morrison, Joe Ferris, Eugene Bolshakov, Josh Nichols, Mike Breen, Marcel Görner, Bence Nagy, Ben Mabey, Eloy Duran, & Tim Pope.
data/Rakefile CHANGED
@@ -13,7 +13,7 @@ namespace :test do
13
13
  end
14
14
 
15
15
  Cucumber::Rake::Task.new(:features) do |t|
16
- t.cucumber_opts = "--format progress"
16
+ t.cucumber_opts = "--format pretty"
17
17
  t.feature_pattern = 'test/rails_root/features/*.feature'
18
18
  end
19
19
  end
@@ -51,13 +51,14 @@ task :default => ['test:all', 'test:features']
51
51
 
52
52
  gem_spec = Gem::Specification.new do |gem_spec|
53
53
  gem_spec.name = "clearance"
54
- gem_spec.version = "0.4.8"
54
+ gem_spec.version = "0.4.9"
55
55
  gem_spec.summary = "Rails authentication for developers who write tests."
56
56
  gem_spec.email = "support@thoughtbot.com"
57
57
  gem_spec.homepage = "http://github.com/thoughtbot/clearance"
58
58
  gem_spec.description = "Simple, complete Rails authentication scheme."
59
59
  gem_spec.authors = ["thoughtbot, inc.", "Dan Croak", "Mike Burns", "Jason Morrison",
60
- "Eugene Bolshakov", "Josh Nichols", "Mike Breen"]
60
+ "Eugene Bolshakov", "Josh Nichols", "Mike Breen", "Joe Ferris",
61
+ "Bence Nagy", "Marcel Görner", "Ben Mabey", "Tim Pope", "Eloy Duran"]
61
62
  gem_spec.files = FileList["[A-Z]*", "{generators,lib,shoulda_macros,rails}/**/*"]
62
63
  end
63
64
 
@@ -40,6 +40,6 @@ In config/environment.rb:
40
40
  3. Clearance depends on root_url, so please make sure that it is defined to
41
41
  *something* in your config/routes.rb:
42
42
 
43
- map.root :controller => 'home'
43
+ map.root :controller => 'users', :action => 'new'
44
44
 
45
45
  *******************************************************************************
@@ -14,7 +14,7 @@
14
14
  <%= form.password_field :password %>
15
15
  </div>
16
16
  <div class="password_field">
17
- <%= form.label :password_confirmation, "Verify password" %>
17
+ <%= form.label :password_confirmation, "Confirm password" %>
18
18
  <%= form.password_field :password_confirmation %>
19
19
  </div>
20
20
  <div class="submit_field">
@@ -8,6 +8,6 @@
8
8
  <%= form.password_field :password %>
9
9
  </div>
10
10
  <div class="password_field">
11
- <%= form.label :password_confirmation, "Verify password" %>
11
+ <%= form.label :password_confirmation, "Confirm password" %>
12
12
  <%= form.password_field :password_confirmation %>
13
13
  </div>
@@ -1,5 +1,5 @@
1
- Fature: Password Reset
2
- In order to sign in even if he forgot his password
1
+ Feature: Password reset
2
+ In order to sign in even if user forgot their password
3
3
  A user
4
4
  Should be able to reset it
5
5
 
@@ -30,3 +30,10 @@ Fature: Password Reset
30
30
  And I sign in as "email@person.com/newpassword"
31
31
  Then I should be signed in
32
32
 
33
+ Scenario: User requests password reset without token
34
+ Given a user exists with an email of "user@one.com"
35
+ When I try to change the password of "user@one.com" without token
36
+ Then I should be forbidden
37
+
38
+
39
+
@@ -7,7 +7,7 @@ Feature: Sign up
7
7
  When I go to the sign up page
8
8
  And I fill in "Email" with "invalidemail"
9
9
  And I fill in "Password" with "password"
10
- And I fill in "Verify Password" with ""
10
+ And I fill in "Confirm password" with ""
11
11
  And I press "Sign Up"
12
12
  Then I should see error messages
13
13
 
@@ -15,7 +15,7 @@ Feature: Sign up
15
15
  When I go to the sign up page
16
16
  And I fill in "Email" with "email@person.com"
17
17
  And I fill in "Password" with "password"
18
- And I fill in "Verify Password" with "password"
18
+ And I fill in "Confirm password" with "password"
19
19
  And I press "Sign Up"
20
20
  Then I should see "instructions for confirming"
21
21
  And a confirmation message should be sent to "email@person.com"
@@ -4,7 +4,13 @@ Then /^I should see error messages$/ do
4
4
  Then %{I should see "error(s)? prohibited"}
5
5
  end
6
6
 
7
- # DB
7
+ # Database
8
+
9
+ Factory.factories.each do |name, factory|
10
+ Given /^an? #{name} exists with an? (.*) of "([^"]*)"$/ do |attr, value|
11
+ Factory(name, attr.gsub(' ', '_') => value)
12
+ end
13
+ end
8
14
 
9
15
  Given /^there is no user with "(.*)"$/ do |email|
10
16
  assert_nil User.find_by_email(email)
@@ -68,6 +74,16 @@ When /^I follow the password reset link sent to "(.*)"$/ do |email|
68
74
  visit edit_user_password_path(:user_id => user, :token => user.token)
69
75
  end
70
76
 
77
+ When /^I try to change the password of "(.*)" without token$/ do |email|
78
+ user = User.find_by_email(email)
79
+ visit edit_user_password_path(:user_id => user)
80
+ end
81
+
82
+ Then /^I should be forbidden$/ do
83
+ assert_response :forbidden
84
+ end
85
+
86
+
71
87
  # Actions
72
88
 
73
89
  When /^I sign in( with "remember me")? as "(.*)\/(.*)"$/ do |remember, email, password|
@@ -90,7 +106,7 @@ end
90
106
 
91
107
  When /^I update my password with "(.*)\/(.*)"$/ do |password, confirmation|
92
108
  And %{I fill in "Choose password" with "#{password}"}
93
- And %{I fill in "Verify password" with "#{confirmation}"}
109
+ And %{I fill in "Confirm password" with "#{confirmation}"}
94
110
  And %{I press "Save this password"}
95
111
  end
96
112
 
@@ -10,7 +10,6 @@ module NavigationHelpers
10
10
  new_session_path
11
11
  when /the password reset request page/i
12
12
  new_password_path
13
-
14
13
 
15
14
  # Add more page name => path mappings here
16
15
 
data/lib/clearance.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'clearance/lib/extensions/errors'
2
+ require 'clearance/lib/extensions/rescue'
1
3
  require 'clearance/app/controllers/application_controller'
2
4
  require 'clearance/app/controllers/confirmations_controller'
3
5
  require 'clearance/app/controllers/passwords_controller'
@@ -8,8 +8,9 @@ module Clearance
8
8
  controller.send(:include, PrivateMethods)
9
9
 
10
10
  controller.class_eval do
11
- before_filter :email_confirmed_user?, :only => :new
12
- before_filter :existing_user?, :only => :new
11
+ before_filter :forbid_confirmed_user, :only => :new
12
+ before_filter :forbid_missing_token, :only => :new
13
+ before_filter :forbid_non_existant_user, :only => :new
13
14
  filter_parameter_logging :token
14
15
  end
15
16
  end
@@ -20,7 +21,9 @@ module Clearance
20
21
  end
21
22
 
22
23
  def create
24
+ @user = User.find_by_id_and_token(params[:user_id], params[:token])
23
25
  @user.confirm_email!
26
+
24
27
  sign_user_in(@user)
25
28
  flash[:success] = "Confirmed email and signed in."
26
29
  redirect_to url_after_create
@@ -30,19 +33,22 @@ module Clearance
30
33
  module PrivateMethods
31
34
  private
32
35
 
33
- def email_confirmed_user?
34
- @user = User.find_by_id(params[:user_id])
35
- if @user.nil?
36
- render :nothing => true, :status => :not_found
37
- elsif @user.email_confirmed?
38
- redirect_to new_session_url
36
+ def forbid_confirmed_user
37
+ user = User.find_by_id(params[:user_id])
38
+ if user && user.email_confirmed?
39
+ raise ActionController::Forbidden, "confirmed user"
39
40
  end
40
41
  end
41
42
 
42
- def existing_user?
43
- @user = User.find_by_id_and_token(params[:user_id], params[:token])
44
- if @user.nil?
45
- render :nothing => true, :status => :not_found
43
+ def forbid_missing_token
44
+ if params[:token].blank?
45
+ raise ActionController::Forbidden, "missing token"
46
+ end
47
+ end
48
+
49
+ def forbid_non_existant_user
50
+ unless User.find_by_id_and_token(params[:user_id], params[:token])
51
+ raise ActionController::Forbidden, "non-existant user"
46
52
  end
47
53
  end
48
54
 
@@ -7,8 +7,9 @@ module Clearance
7
7
  controller.send(:include, Actions)
8
8
  controller.send(:include, PrivateMethods)
9
9
 
10
- controller.class_eval do
11
- before_filter :existing_user?, :only => [:edit, :update]
10
+ controller.class_eval do
11
+ before_filter :forbid_missing_token, :only => [:edit, :update]
12
+ before_filter :forbid_non_existant_user, :only => [:edit, :update]
12
13
  filter_parameter_logging :password, :password_confirmation
13
14
  end
14
15
  end
@@ -32,9 +33,12 @@ module Clearance
32
33
  end
33
34
 
34
35
  def edit
36
+ @user = User.find_by_id_and_token(params[:user_id], params[:token])
35
37
  end
36
38
 
37
39
  def update
40
+ @user = User.find_by_id_and_token(params[:user_id], params[:token])
41
+
38
42
  if @user.update_password(params[:user])
39
43
  sign_user_in(@user)
40
44
  redirect_to url_after_update
@@ -47,10 +51,15 @@ module Clearance
47
51
  module PrivateMethods
48
52
  private
49
53
 
50
- def existing_user?
51
- @user = User.find_by_id_and_token(params[:user_id], params[:token])
52
- if @user.nil?
53
- render :nothing => true, :status => :not_found
54
+ def forbid_missing_token
55
+ if params[:token].blank?
56
+ raise ActionController::Forbidden, "missing token"
57
+ end
58
+ end
59
+
60
+ def forbid_non_existant_user
61
+ unless User.find_by_id_and_token(params[:user_id], params[:token])
62
+ raise ActionController::Forbidden, "non-existant user"
54
63
  end
55
64
  end
56
65
 
@@ -0,0 +1,4 @@
1
+ module ActionController
2
+ class Forbidden < StandardError
3
+ end
4
+ end
@@ -0,0 +1 @@
1
+ ActionController::Base.rescue_responses.update('ActionController::Forbidden' => :forbidden)
@@ -8,9 +8,14 @@ module Clearance
8
8
 
9
9
  should_filter_params :token
10
10
 
11
- context "Given a user whose email has not been confirmed" do
11
+ context "a user whose email has not been confirmed" do
12
12
  setup { @user = Factory(:user) }
13
13
 
14
+ should "have a token" do
15
+ assert_not_nil @user.token
16
+ assert_not_equal "", @user.token
17
+ end
18
+
14
19
  context "on GET to #new with correct id and token" do
15
20
  setup do
16
21
  get :new, :user_id => @user.to_param, :token => @user.token
@@ -22,53 +27,39 @@ module Clearance
22
27
  should_redirect_to_url_after_create
23
28
  end
24
29
 
25
- context "on GET to #new with incorrect token" do
26
- setup do
27
- token = ""
28
- assert_not_equal token, @user.token
29
-
30
- get :new, :user_id => @user.to_param, :token => token
30
+ context "with an incorrect token" do
31
+ setup do
32
+ @bad_token = "bad token"
33
+ assert_not_equal @bad_token, @user.token
34
+ end
35
+
36
+ should_forbid "on GET to #new with incorrect token" do
37
+ get :new, :user_id => @user.to_param, :token => @bad_token
31
38
  end
32
-
33
- should_respond_with :not_found
34
- should_render_nothing
39
+ end
40
+
41
+ should_forbid "on GET to #new with blank token" do
42
+ get :new, :user_id => @user.to_param, :token => ""
43
+ end
44
+
45
+ should_forbid "on GET to #new with no token" do
46
+ get :new, :user_id => @user.to_param
35
47
  end
36
48
  end
37
49
 
38
- context "Given a user whose email has been confirmed" do
50
+ context "a user with email confirmed" do
39
51
  setup { @user = Factory(:email_confirmed_user) }
40
52
 
41
- context "on GET to #new with correct id and token" do
42
- setup do
43
- get :new, :user_id => @user.to_param, :token => @user.token
44
- end
45
-
46
- should_not_be_signed_in
47
- should_redirect_to 'new_session_url'
48
- end
49
-
50
- context "on GET to #new with incorrect token" do
51
- setup do
52
- token = ""
53
- assert_not_equal token, @user.token
54
-
55
- get :new, :user_id => @user.to_param, :token => token
56
- end
57
-
58
- should_not_be_signed_in
59
- should_redirect_to 'new_session_url'
53
+ should_forbid "on GET to #new with correct id" do
54
+ get :new, :user_id => @user.to_param
60
55
  end
61
56
  end
62
57
 
63
- context "Given no user records" do
58
+ context "no users" do
64
59
  setup { assert_equal 0, User.count }
65
- context "on GET to #new with nonexistent id and token" do
66
- setup do
67
- get :new, :user_id => '123', :token => '123'
68
- end
69
-
70
- should_respond_with :not_found
71
- should_render_nothing
60
+
61
+ should_forbid "on GET to #new with nonexistent id and token" do
62
+ get :new, :user_id => '123', :token => '123'
72
63
  end
73
64
  end
74
65
 
@@ -9,163 +9,169 @@ module Clearance
9
9
  should_route :get, '/users/1/password/edit',
10
10
  :action => 'edit', :user_id => '1'
11
11
 
12
- context "with a confirmed user" do
12
+ context "a user with confirmed email" do
13
13
  setup do
14
- @user = Factory(:user)
14
+ @user = Factory(:email_confirmed_user)
15
15
  @user.confirm_email!
16
16
  end
17
17
 
18
- context 'A GET to #new' do
18
+ context "on GET to #new" do
19
19
  setup { get :new, :user_id => @user.to_param }
20
20
 
21
21
  should_respond_with :success
22
22
  should_render_template "new"
23
23
  end
24
24
 
25
- context "A POST to #create" do
26
- context "with an existing user's email address" do
25
+ context "on POST to #create" do
26
+ context "with correct email address" do
27
27
  setup do
28
28
  ActionMailer::Base.deliveries.clear
29
29
  post :create, :password => { :email => @user.email }
30
30
  end
31
31
 
32
- should_send_the_change_your_password_email
32
+ should "generate a token for the change your password email" do
33
+ assert_not_nil @user.reload.token
34
+ end
35
+
36
+ should "send the change your password email" do
37
+ assert_sent_email do |email|
38
+ email.subject =~ /change your password/i
39
+ end
40
+ end
41
+
33
42
  should_set_the_flash_to /password/i
34
43
  should_redirect_to_url_after_create
35
44
  end
36
45
 
37
- context "with a non-existent email address" do
46
+ context "with incorrect email address" do
38
47
  setup do
39
48
  email = "user1@example.com"
40
49
  assert ! User.exists?(['email = ?', email])
41
50
  ActionMailer::Base.deliveries.clear
51
+ assert_nil @user.reload.token
42
52
 
43
53
  post :create, :password => { :email => email }
44
54
  end
45
55
 
46
- should_not_send_the_change_your_password_email
56
+ should "not generate a token for the change your password email" do
57
+ assert_nil @user.reload.token
58
+ end
59
+
60
+ should "not send a password reminder email" do
61
+ assert ActionMailer::Base.deliveries.empty?
62
+ end
47
63
 
48
64
  should "set a :notice flash" do
49
65
  assert_not_nil flash.now[:notice]
50
66
  end
51
67
 
52
- should_render_template "new"
68
+ should_render_template :new
53
69
  end
54
70
  end
71
+ end
72
+
73
+ context "a user with confirmed email and forgotten password" do
74
+ setup do
75
+ @user = Factory(:email_confirmed_user)
76
+ @user.forgot_password!
77
+ end
55
78
 
56
- context 'who requested password recovery' do
57
- setup { @user.forgot_password! }
58
-
59
- context "A GET to #edit" do
60
- context "with an existing user's id and token" do
61
- setup do
62
- get :edit, :user_id => @user.to_param, :token => @user.token
63
- end
64
-
65
- should "find the user with the given id and token" do
66
- assert_equal @user, assigns(:user)
67
- end
68
-
69
- should_respond_with :success
70
- should_render_template "edit"
71
- should_display_a_password_update_form
72
- end
73
-
74
- context "with an existing user's id but not token" do
75
- setup do
76
- get :edit, :user_id => @user.to_param, :token => ""
77
- end
78
-
79
- should_respond_with :not_found
80
- should_render_nothing
81
- end
79
+ context "on GET to #edit with correct id and token" do
80
+ setup do
81
+ get :edit, :user_id => @user.to_param, :token => @user.token
82
82
  end
83
-
84
- context "A PUT to #update" do
85
- context "with a matching password and password confirmation" do
86
- setup do
87
- new_password = "new_password"
88
- @encrypted_new_password = @user.encrypt(new_password)
89
- assert_not_equal @encrypted_new_password, @user.encrypted_password
90
-
91
- put(:update,
92
- :user_id => @user,
93
- :token => @user.token,
94
- :user => {
95
- :password => new_password,
96
- :password_confirmation => new_password
97
- })
98
- @user.reload
99
- end
100
-
101
- should "update the user's password" do
102
- assert_equal @encrypted_new_password, @user.encrypted_password
103
- end
104
-
105
- should "clear the token" do
106
- assert_nil @user.token
107
- end
108
-
109
- should_be_signed_in_as { @user }
110
- should_redirect_to_url_after_update
111
- end
112
-
113
- context "with password but blank password confirmation" do
114
- setup do
115
- new_password = "new_password"
116
- @encrypted_new_password = @user.encrypt(new_password)
117
-
118
- put(:update,
119
- :user_id => @user.to_param,
120
- :token => @user.token,
121
- :user => {
122
- :password => new_password,
123
- :password_confirmation => ''
124
- })
125
- @user.reload
126
- end
127
-
128
- should "not update the user's password" do
129
- assert_not_equal @encrypted_new_password, @user.encrypted_password
130
- end
131
-
132
- should "not clear the token" do
133
- assert_not_nil @user.token
134
- end
135
-
136
- should_not_be_signed_in
137
- should_respond_with :success
138
- should_render_template :edit
139
-
140
- should_display_a_password_update_form
141
- end
142
-
143
- context "with an existing user's id but not token" do
144
- setup do
145
- new_password = "new_password"
146
- @encrypted_new_password = @user.encrypt(new_password)
147
- put(:update,
148
- :user_id => @user.to_param,
149
- :token => "",
150
- :user => {
151
- :password => new_password,
152
- :password => new_password
153
- })
154
- end
155
-
156
- should "not update the user's password" do
157
- assert_not_equal @encrypted_new_password, @user.encrypted_password
158
- end
159
-
160
- should_not_be_signed_in
161
- should_respond_with :not_found
162
- should_render_nothing
163
- end
83
+
84
+ should "find the user" do
85
+ assert_equal @user, assigns(:user)
164
86
  end
165
-
87
+
88
+ should_respond_with :success
89
+ should_render_template "edit"
90
+ should_display_a_password_update_form
91
+ end
92
+
93
+ should_forbid "on GET to #edit with correct id but blank token" do
94
+ get :edit, :user_id => @user.to_param, :token => ""
95
+ end
96
+
97
+ should_forbid "on GET to #edit with correct id but no token" do
98
+ get :edit, :user_id => @user.to_param
166
99
  end
167
100
 
168
- end
101
+ context "on PUT to #update with matching password and password confirmation" do
102
+ setup do
103
+ new_password = "new_password"
104
+ @encrypted_new_password = @user.encrypt(new_password)
105
+ assert_not_equal @encrypted_new_password, @user.encrypted_password
106
+
107
+ put(:update,
108
+ :user_id => @user,
109
+ :token => @user.token,
110
+ :user => {
111
+ :password => new_password,
112
+ :password_confirmation => new_password
113
+ })
114
+ @user.reload
115
+ end
116
+
117
+ should "update password" do
118
+ assert_equal @encrypted_new_password, @user.encrypted_password
119
+ end
120
+
121
+ should "clear token" do
122
+ assert_nil @user.token
123
+ end
124
+
125
+ should_be_signed_in_as { @user }
126
+ should_redirect_to_url_after_update
127
+ end
128
+
129
+ context "on PUT to #update with password but blank password confirmation" do
130
+ setup do
131
+ new_password = "new_password"
132
+ @encrypted_new_password = @user.encrypt(new_password)
133
+
134
+ put(:update,
135
+ :user_id => @user.to_param,
136
+ :token => @user.token,
137
+ :user => {
138
+ :password => new_password,
139
+ :password_confirmation => ''
140
+ })
141
+ @user.reload
142
+ end
143
+
144
+ should "not update password" do
145
+ assert_not_equal @encrypted_new_password, @user.encrypted_password
146
+ end
147
+
148
+ should "not clear token" do
149
+ assert_not_nil @user.token
150
+ end
151
+
152
+ should_not_be_signed_in
153
+ should_respond_with :success
154
+ should_render_template :edit
155
+
156
+ should_display_a_password_update_form
157
+ end
158
+
159
+ should_forbid "on PUT to #update with id but no token" do
160
+ put :update, :user_id => @user.to_param, :token => ""
161
+ end
162
+ end
163
+
164
+ context "given two users and user one signs in" do
165
+ setup do
166
+ @user_one = Factory(:user)
167
+ @user_two = Factory(:user)
168
+ sign_in_as @user_one
169
+ end
170
+
171
+ should_forbid "when user one tries to change user two's password on GET with no token" do
172
+ get :edit, :user_id => @user_two.to_param
173
+ end
174
+ end
169
175
  end
170
176
  end
171
177
 
@@ -53,6 +53,16 @@ module Clearance
53
53
  end
54
54
  end
55
55
 
56
+ # HTTP FLUENCY
57
+
58
+ def should_forbid(description, &block)
59
+ should "forbid #{description}" do
60
+ assert_raises ActionController::Forbidden do
61
+ instance_eval(&block)
62
+ end
63
+ end
64
+ end
65
+
56
66
  # CONTEXTS
57
67
 
58
68
  def signed_in_user_context(&blk)
@@ -140,30 +150,6 @@ module Clearance
140
150
  end
141
151
  end
142
152
 
143
- # EMAILS
144
-
145
- def should_send_the_change_your_password_email
146
- should "generate a token for the change your password email" do
147
- assert_not_nil @user.reload.token
148
- end
149
-
150
- should "send the change your password email" do
151
- assert_sent_email do |email|
152
- email.subject =~ /change your password/i
153
- end
154
- end
155
- end
156
-
157
- def should_not_send_the_change_your_password_email
158
- should "generate a token for the change your password email" do
159
- assert_nil @user.reload.token
160
- end
161
-
162
- should "not send a password reminder email" do
163
- assert ActionMailer::Base.deliveries.empty?
164
- end
165
- end
166
-
167
153
  # FORMS
168
154
 
169
155
  def should_display_a_password_update_form
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thoughtbot-clearance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8
4
+ version: 0.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoughtbot, inc.
@@ -11,11 +11,17 @@ authors:
11
11
  - Eugene Bolshakov
12
12
  - Josh Nichols
13
13
  - Mike Breen
14
+ - Joe Ferris
15
+ - Bence Nagy
16
+ - "Marcel G\xC3\xB6rner"
17
+ - Ben Mabey
18
+ - Tim Pope
19
+ - Eloy Duran
14
20
  autorequire:
15
21
  bindir: bin
16
22
  cert_chain: []
17
23
 
18
- date: 2009-02-15 21:00:00 -08:00
24
+ date: 2009-02-19 21:00:00 -08:00
19
25
  default_executable:
20
26
  dependencies: []
21
27
 
@@ -103,6 +109,10 @@ files:
103
109
  - lib/clearance/app/models
104
110
  - lib/clearance/app/models/clearance_mailer.rb
105
111
  - lib/clearance/app/models/user.rb
112
+ - lib/clearance/lib
113
+ - lib/clearance/lib/extensions
114
+ - lib/clearance/lib/extensions/errors.rb
115
+ - lib/clearance/lib/extensions/rescue.rb
106
116
  - lib/clearance/test
107
117
  - lib/clearance/test/functional
108
118
  - lib/clearance/test/functional/confirmations_controller_test.rb