clearance 0.10.5 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of clearance might be problematic. Click here for more details.

data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ 0.11.0
2
+ -------------------
3
+
4
+ * Removing password confirmation.
5
+ * Use ActiveSupport::Concern and ActiveSupport::SecureRandom to clean up code.
6
+ * New controller#authenticate(params) method. Redefine username & password or other styles of authentication.
7
+ * before_filter :authenticate API replaced with more aptly-named before_filter :authorize.
8
+
1
9
  0.10.5
2
10
  -------------------
3
11
 
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Clearance
2
2
  =========
3
3
 
4
- Rails authentication with email & password.
4
+ Rails authentication & authorization with email & password.
5
5
 
6
6
  [We have clearance, Clarence.](http://www.youtube.com/watch?v=fVq4_HhBK8Y)
7
7
 
@@ -11,9 +11,8 @@ Help
11
11
  ----
12
12
 
13
13
  * [Documentation](http://rdoc.info/gems/clearance) at RDoc.info.
14
- * [Patches welcome](http://github.com/thoughtbot/clearance/issues) via Github Issues.
15
- * [#thoughtbot](irc://irc.freenode.net/thoughtbot) IRC channel on freenode.
16
- * [Mailing list](http://groups.google.com/group/thoughtbot-clearance) on Google Groups.
14
+ * [Patches and bugs](http://github.com/thoughtbot/clearance/issues) at Github Issues.
15
+ * [Mailing list](http://groups.google.com/group/thoughtbot-clearance) at Google Groups.
17
16
 
18
17
  Installation
19
18
  ------------
@@ -40,11 +39,11 @@ series of Clearance if you have a Rails 2 app.
40
39
  Usage
41
40
  -----
42
41
 
43
- If you want to authenticate users for a controller action, use the authenticate
42
+ If you want to authorize users for a controller action, use the authorize
44
43
  method in a before_filter.
45
44
 
46
45
  class WidgetsController < ApplicationController
47
- before_filter :authenticate
46
+ before_filter :authorize
48
47
  def index
49
48
  @widgets = Widget.all
50
49
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.5
1
+ 0.11.0
@@ -1,7 +1,7 @@
1
1
  class Clearance::PasswordsController < ApplicationController
2
2
  unloadable
3
3
 
4
- skip_before_filter :authenticate, :only => [:new, :create, :edit, :update]
4
+ skip_before_filter :authorize, :only => [:new, :create, :edit, :update]
5
5
  before_filter :forbid_missing_token, :only => [:edit, :update]
6
6
  before_filter :forbid_non_existent_user, :only => [:edit, :update]
7
7
 
@@ -31,8 +31,7 @@ class Clearance::PasswordsController < ApplicationController
31
31
  @user = ::User.find_by_id_and_confirmation_token(
32
32
  params[:user_id], params[:token])
33
33
 
34
- if @user.update_password(params[:user][:password],
35
- params[:user][:password_confirmation])
34
+ if @user.update_password(params[:user][:password])
36
35
  sign_in(@user)
37
36
  flash_success_after_update
38
37
  redirect_to(url_after_update)
@@ -1,7 +1,7 @@
1
1
  class Clearance::SessionsController < ApplicationController
2
2
  unloadable
3
3
 
4
- skip_before_filter :authenticate, :only => [:new, :create, :destroy]
4
+ skip_before_filter :authorize, :only => [:new, :create, :destroy]
5
5
  protect_from_forgery :except => :create
6
6
 
7
7
  def new
@@ -9,8 +9,7 @@ class Clearance::SessionsController < ApplicationController
9
9
  end
10
10
 
11
11
  def create
12
- @user = ::User.authenticate(params[:session][:email],
13
- params[:session][:password])
12
+ @user = authenticate(params)
14
13
  if @user.nil?
15
14
  flash_failure_after_create
16
15
  render :template => 'sessions/new', :status => :unauthorized
@@ -1,7 +1,7 @@
1
1
  class Clearance::UsersController < ApplicationController
2
2
  unloadable
3
3
 
4
- skip_before_filter :authenticate, :only => [:new, :create]
4
+ skip_before_filter :authorize, :only => [:new, :create]
5
5
  before_filter :redirect_to_root, :only => [:new, :create], :if => :signed_in?
6
6
 
7
7
  def new
@@ -10,7 +10,7 @@ class Clearance::UsersController < ApplicationController
10
10
  end
11
11
 
12
12
  def create
13
- @user = ::User.new params[:user]
13
+ @user = ::User.new(params[:user])
14
14
  if @user.save
15
15
  flash_notice_after_create
16
16
  sign_in(@user)
@@ -23,7 +23,7 @@ class Clearance::UsersController < ApplicationController
23
23
  private
24
24
 
25
25
  def flash_notice_after_create
26
- flash[:notice] = translate(:deliver_confirmation,
26
+ flash[:notice] = translate(:signed_up,
27
27
  :scope => [:clearance, :controllers, :users],
28
28
  :default => "You are now signed up.")
29
29
  end
@@ -12,10 +12,6 @@
12
12
  <%= form.label :password, "Choose password" %>
13
13
  <%= form.password_field :password %>
14
14
  </div>
15
- <div class="password_field">
16
- <%= form.label :password_confirmation, "Confirm password" %>
17
- <%= form.password_field :password_confirmation %>
18
- </div>
19
15
  <div class="submit_field">
20
16
  <%= form.submit "Save this password" %>
21
17
  </div>
@@ -7,7 +7,3 @@
7
7
  <%= form.label :password %>
8
8
  <%= form.password_field :password %>
9
9
  </div>
10
- <div class="password_field">
11
- <%= form.label :password_confirmation, "Confirm password" %>
12
- <%= form.password_field :password_confirmation %>
13
- </div>
data/clearance.gemspec CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
9
9
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
10
  s.authors = ["Dan Croak", "Mike Burns", "Jason Morrison", "Joe Ferris", "Eugene Bolshakov", "Nick Quaranto", "Josh Nichols", "Mike Breen", "Marcel G\303\266rner", "Bence Nagy", "Ben Mabey", "Eloy Duran", "Tim Pope", "Mihai Anca", "Mark Cornick", "Shay Arnett", "Jon Yurek", "Chad Pytel"]
11
11
  s.date = Date.today.to_s
12
- s.summary = %q{Rails authentication with email & password.}
13
- s.description = %q{Rails authentication with email & password.}
12
+ s.summary = %q{Rails authentication & authorization with email & password.}
13
+ s.description = %q{Rails authentication & authorization with email & password.}
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE",
16
16
  "README.md"
@@ -15,24 +15,14 @@ Feature: Password reset
15
15
  Then I should see "instructions for changing your password"
16
16
  And a password reset message should be sent to "email@example.com"
17
17
 
18
- Scenario: User is signed up updated his password and tries blank password and confirmation
18
+ Scenario: User tries to reset his password with a blank password
19
19
  Given I signed up with "email@example.com/password"
20
20
  And I go to the password reset request page
21
21
  Then I should see an email field
22
22
  And I fill in "Email address" with "email@example.com"
23
23
  And I press "Reset password"
24
24
  When I follow the password reset link sent to "email@example.com"
25
- And I update my password with "/"
26
- Then I should see an error message
27
- And I should be signed out
28
-
29
- Scenario: User is signed up updated his password and types wrong confirmation
30
- Given I signed up with "email@example.com/password"
31
- And I go to the password reset request page
32
- And I fill in "Email address" with "email@example.com"
33
- And I press "Reset password"
34
- When I follow the password reset link sent to "email@example.com"
35
- And I update my password with "newpassword/wrongconfirmation"
25
+ And I update my password with ""
36
26
  Then I should see an error message
37
27
  And I should be signed out
38
28
 
@@ -42,7 +32,7 @@ Feature: Password reset
42
32
  And I fill in "Email address" with "email@example.com"
43
33
  And I press "Reset password"
44
34
  When I follow the password reset link sent to "email@example.com"
45
- And I update my password with "newpassword/newpassword"
35
+ And I update my password with "newpassword"
46
36
  Then I should be signed in
47
37
  When I sign out
48
38
  Then I should be signed out
@@ -55,6 +45,6 @@ Feature: Password reset
55
45
  And I fill in "Email address" with "email@example.com"
56
46
  And I press "Reset password"
57
47
  When I follow the password reset link sent to "email@example.com"
58
- And I update my password with "newpassword/newpassword"
48
+ And I update my password with "newpassword"
59
49
  Then I should be signed in
60
50
 
@@ -8,16 +8,20 @@ Feature: Sign up
8
8
  When I go to the sign up page
9
9
  Then I should see an email field
10
10
 
11
- Scenario: Visitor signs up with invalid data
11
+ Scenario: Visitor signs up with invalid email
12
12
  When I fill in "Email" with "invalidemail"
13
13
  And I fill in "Password" with "password"
14
- And I fill in "Confirm password" with ""
15
14
  And I press "Sign up"
16
- Then I should see error messages
15
+ Then I should see "Email is invalid"
16
+
17
+ Scenario: Visitor signs up with blank password
18
+ When I fill in "Email" with "email@example.com"
19
+ And I fill in "Password" with ""
20
+ And I press "Sign up"
21
+ Then I should see "Password can't be blank"
17
22
 
18
23
  Scenario: Visitor signs up with valid data
19
- When I fill in "Email" with "email@person.com"
24
+ When I fill in "Email" with "email@example.com"
20
25
  And I fill in "Password" with "password"
21
- And I fill in "Confirm password" with "password"
22
26
  And I press "Sign up"
23
27
  Then I should see "signed up"
@@ -24,9 +24,8 @@ end
24
24
 
25
25
  Given /^(?:I am|I have|I) signed up (?:as|with) "(.*)\/(.*)"$/ do |email, password|
26
26
  Factory(:user,
27
- :email => email,
28
- :password => password,
29
- :password_confirmation => password)
27
+ :email => email,
28
+ :password => password)
30
29
  end
31
30
 
32
31
  Given /^a user "([^"]*)" exists without a salt, remember token, or password$/ do |email|
@@ -71,9 +70,9 @@ Then /^a password reset message should be sent to "(.*)"$/ do |email|
71
70
  assert !user.confirmation_token.blank?
72
71
  assert !ActionMailer::Base.deliveries.empty?
73
72
  result = ActionMailer::Base.deliveries.any? do |email|
74
- email.to == [user.email] &&
73
+ email.to == [user.email] &&
75
74
  email.subject =~ /password/i &&
76
- email.body =~ /#{user.confirmation_token}/
75
+ email.body =~ /#{user.confirmation_token}/
77
76
  end
78
77
  assert result
79
78
  end
@@ -111,9 +110,8 @@ When /^I request password reset link to be sent to "(.*)"$/ do |email|
111
110
  And %{I press "Reset password"}
112
111
  end
113
112
 
114
- When /^I update my password with "(.*)\/(.*)"$/ do |password, confirmation|
113
+ When /^I update my password with "(.*)"$/ do |password|
115
114
  And %{I fill in "Choose password" with "#{password}"}
116
- And %{I fill in "Confirm password" with "#{confirmation}"}
117
115
  And %{I press "Save this password"}
118
116
  end
119
117
 
@@ -1,138 +1,135 @@
1
1
  module Clearance
2
2
  module Authentication
3
-
4
- def self.included(controller) # :nodoc:
5
- controller.send(:include, InstanceMethods)
6
- controller.extend(ClassMethods)
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ helper_method :current_user, :signed_in?, :signed_out?
7
+ hide_action :current_user, :current_user=,
8
+ :signed_in?, :signed_out?,
9
+ :sign_in, :sign_out,
10
+ :authorize, :deny_access
7
11
  end
8
12
 
9
- module ClassMethods
10
- def self.extended(controller)
11
- controller.helper_method :current_user, :signed_in?, :signed_out?
12
- controller.hide_action :current_user, :current_user=,
13
- :signed_in?, :signed_out?,
14
- :sign_in, :sign_out,
15
- :authenticate, :deny_access
16
-
17
- end
13
+ # User in the current cookie
14
+ #
15
+ # @return [User, nil]
16
+ def current_user
17
+ @_current_user ||= user_from_cookie
18
18
  end
19
19
 
20
- module InstanceMethods
21
- # User in the current cookie
22
- #
23
- # @return [User, nil]
24
- def current_user
25
- @_current_user ||= user_from_cookie
26
- end
27
-
28
- # Set the current user
29
- #
30
- # @param [User]
31
- def current_user=(user)
32
- @_current_user = user
33
- end
34
-
35
- # Is the current user signed in?
36
- #
37
- # @return [true, false]
38
- def signed_in?
39
- ! current_user.nil?
40
- end
20
+ # Set the current user
21
+ #
22
+ # @param [User]
23
+ def current_user=(user)
24
+ @_current_user = user
25
+ end
41
26
 
42
- # Is the current user signed out?
43
- #
44
- # @return [true, false]
45
- def signed_out?
46
- current_user.nil?
47
- end
27
+ # Is the current user signed in?
28
+ #
29
+ # @return [true, false]
30
+ def signed_in?
31
+ ! current_user.nil?
32
+ end
48
33
 
49
- # Deny the user access if they are signed out.
50
- #
51
- # @example
52
- # before_filter :authenticate
53
- def authenticate
54
- deny_access unless signed_in?
55
- end
34
+ # Is the current user signed out?
35
+ #
36
+ # @return [true, false]
37
+ def signed_out?
38
+ current_user.nil?
39
+ end
56
40
 
57
- # Sign user in to cookie.
58
- #
59
- # @param [User]
60
- #
61
- # @example
62
- # sign_in(@user)
63
- def sign_in(user)
64
- if user
65
- cookies[:remember_token] = {
66
- :value => user.remember_token,
67
- :expires => Clearance.configuration.cookie_expiration.call
68
- }
69
- self.current_user = user
70
- end
41
+ # Sign user in to cookie.
42
+ #
43
+ # @param [User]
44
+ #
45
+ # @example
46
+ # sign_in(@user)
47
+ def sign_in(user)
48
+ if user
49
+ cookies[:remember_token] = {
50
+ :value => user.remember_token,
51
+ :expires => Clearance.configuration.cookie_expiration.call
52
+ }
53
+ self.current_user = user
71
54
  end
55
+ end
72
56
 
73
- # Sign user out of cookie.
74
- #
75
- # @example
76
- # sign_out
77
- def sign_out
78
- current_user.reset_remember_token! if current_user
79
- cookies.delete(:remember_token)
80
- self.current_user = nil
81
- end
57
+ # Sign user out of cookie.
58
+ #
59
+ # @example
60
+ # sign_out
61
+ def sign_out
62
+ current_user.reset_remember_token! if current_user
63
+ cookies.delete(:remember_token)
64
+ self.current_user = nil
65
+ end
82
66
 
83
- # Store the current location and redirect to sign in.
84
- # Display a failure flash message if included.
85
- #
86
- # @param [String] optional flash message to display to denied user
87
- def deny_access(flash_message = nil)
88
- store_location
89
- flash[:failure] = flash_message if flash_message
90
- redirect_to(sign_in_url)
91
- end
67
+ # Find the user by the given params or return nil.
68
+ # By default, uses email and password.
69
+ # Redefine this method and User.authenticate for other mechanisms
70
+ # such as username and password.
71
+ #
72
+ # @example
73
+ # @user = authenticate(params)
74
+ def authenticate(params)
75
+ ::User.authenticate(params[:session][:email],
76
+ params[:session][:password])
77
+ end
92
78
 
93
- protected
79
+ # Deny the user access if they are signed out.
80
+ #
81
+ # @example
82
+ # before_filter :authorize
83
+ def authorize
84
+ deny_access unless signed_in?
85
+ end
94
86
 
95
- # CSRF protection in Rails >= 3.0.4
96
- # http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails
97
- def handle_unverified_request
98
- super
99
- sign_out
100
- end
87
+ # Store the current location and redirect to sign in.
88
+ # Display a failure flash message if included.
89
+ #
90
+ # @param [String] optional flash message to display to denied user
91
+ def deny_access(flash_message = nil)
92
+ store_location
93
+ flash[:failure] = flash_message if flash_message
94
+ redirect_to(sign_in_url)
95
+ end
101
96
 
102
- def user_from_cookie
103
- if token = cookies[:remember_token]
104
- ::User.find_by_remember_token(token)
105
- end
106
- end
97
+ # CSRF protection in Rails >= 3.0.4
98
+ # http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails
99
+ def handle_unverified_request
100
+ super
101
+ sign_out
102
+ end
107
103
 
108
- def sign_user_in(user)
109
- warn "[DEPRECATION] sign_user_in: unnecessary. use sign_in(user) instead."
110
- sign_in(user)
111
- end
104
+ protected
112
105
 
113
- def store_location
114
- if request.get?
115
- session[:return_to] = request.fullpath
116
- end
106
+ def user_from_cookie
107
+ if token = cookies[:remember_token]
108
+ ::User.find_by_remember_token(token)
117
109
  end
110
+ end
118
111
 
119
- def redirect_back_or(default)
120
- redirect_to(return_to || default)
121
- clear_return_to
112
+ def store_location
113
+ if request.get?
114
+ session[:return_to] = request.fullpath
122
115
  end
116
+ end
123
117
 
124
- def return_to
125
- session[:return_to] || params[:return_to]
126
- end
118
+ def redirect_back_or(default)
119
+ redirect_to(return_to || default)
120
+ clear_return_to
121
+ end
127
122
 
128
- def clear_return_to
129
- session[:return_to] = nil
130
- end
123
+ def return_to
124
+ session[:return_to] || params[:return_to]
125
+ end
131
126
 
132
- def redirect_to_root
133
- redirect_to('/')
134
- end
127
+ def clear_return_to
128
+ session[:return_to] = nil
135
129
  end
136
130
 
131
+ def redirect_to_root
132
+ redirect_to('/')
133
+ end
137
134
  end
138
135
  end
@@ -4,7 +4,7 @@ require "rails"
4
4
  module Clearance
5
5
  class Engine < Rails::Engine
6
6
  initializer "clearance.filter" do |app|
7
- app.config.filter_parameters += [:token, :password, :password_confirmation]
7
+ app.config.filter_parameters += [:token, :password]
8
8
  end
9
9
  end
10
10
  end
@@ -2,6 +2,7 @@ require 'digest/sha1'
2
2
 
3
3
  module Clearance
4
4
  module User
5
+ extend ActiveSupport::Concern
5
6
 
6
7
  # Hook for all Clearance::User modules.
7
8
  #
@@ -9,192 +10,165 @@ module Clearance
9
10
  # extend and include à la carte.
10
11
  #
11
12
  # @example
12
- # extend ClassMethods
13
- # include InstanceMethods
14
- # include AttrAccessor
15
13
  # include Callbacks
16
14
  #
17
- # @see ClassMethods
18
- # @see InstanceMethods
19
- # @see AttrAccessor
20
15
  # @see Validations
21
16
  # @see Callbacks
22
- def self.included(model)
23
- model.extend(ClassMethods)
17
+ included do
18
+ attr_accessor :password, :password_changing
24
19
 
25
- model.send(:include, InstanceMethods)
26
- model.send(:include, AttrAccessor)
27
- model.send(:include, Validations)
28
- model.send(:include, Callbacks)
20
+ include Validations
21
+ include Callbacks
29
22
  end
30
23
 
31
- module AttrAccessor
32
- # Hook for attr_accessor virtual attributes.
24
+ module ClassMethods
25
+ # Authenticate with email and password.
33
26
  #
34
- # :password, :password_confirmation
35
- def self.included(model)
36
- model.class_eval do
37
- attr_accessor :password, :password_confirmation
38
- private
39
- attr_accessor :password_changing
40
- end
27
+ # @param [String, String] email and password
28
+ # @return [User, nil] authenticated user or nil
29
+ # @example
30
+ # User.authenticate("email@example.com", "password")
31
+ def authenticate(email, password)
32
+ return nil unless user = find_by_email(email.to_s.downcase)
33
+ return user if user.authenticated?(password)
41
34
  end
42
35
  end
43
36
 
44
37
  module Validations
38
+ extend ActiveSupport::Concern
39
+
45
40
  # Hook for validations.
46
41
  #
47
42
  # :email must be present, unique, formatted
48
43
  #
49
44
  # If password is required,
50
45
  # :password must be present, confirmed
51
- def self.included(model)
52
- model.class_eval do
53
- validates_presence_of :email, :unless => :email_optional?
54
- validates_uniqueness_of :email, :case_sensitive => false, :allow_blank => true
55
- validates_format_of :email, :with => %r{^[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$}i, :allow_blank => true
56
-
57
- validates_presence_of :password, :unless => :password_optional?
58
- validates_confirmation_of :password
59
- end
46
+ included do
47
+ validates_presence_of :email, :unless => :email_optional?
48
+ validates_uniqueness_of :email, :case_sensitive => false, :allow_blank => true
49
+ validates_format_of :email, :with => %r{^[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$}i, :allow_blank => true
50
+
51
+ validates_presence_of :password, :unless => :password_optional?
60
52
  end
61
53
  end
62
54
 
63
55
  module Callbacks
56
+ extend ActiveSupport::Concern
57
+
64
58
  # Hook for callbacks.
65
59
  #
66
60
  # salt, token, password encryption are handled before_save.
67
- def self.included(model)
68
- model.class_eval do
69
- before_validation :downcase_email
70
- before_save :initialize_salt,
71
- :encrypt_password
72
- before_create :generate_remember_token
73
- end
61
+ included do
62
+ before_validation :downcase_email
63
+ before_save :initialize_salt,
64
+ :encrypt_password
65
+ before_create :generate_remember_token
74
66
  end
75
67
  end
76
68
 
77
- module InstanceMethods
78
- # Am I authenticated with given password?
79
- #
80
- # @param [String] plain-text password
81
- # @return [true, false]
82
- # @example
83
- # user.authenticated?('password')
84
- def authenticated?(password)
85
- encrypted_password == encrypt(password)
86
- end
87
-
88
- # Set the remember token.
89
- #
90
- # @deprecated Use {#reset_remember_token!} instead
91
- def remember_me!
92
- warn "[DEPRECATION] remember_me!: use reset_remember_token! instead"
93
- reset_remember_token!
94
- end
95
-
96
- # Reset the remember token.
97
- #
98
- # @example
99
- # user.reset_remember_token!
100
- def reset_remember_token!
101
- generate_remember_token
102
- save(:validate => false)
103
- end
69
+ # Am I authenticated with given password?
70
+ #
71
+ # @param [String] plain-text password
72
+ # @return [true, false]
73
+ # @example
74
+ # user.authenticated?('password')
75
+ def authenticated?(password)
76
+ encrypted_password == encrypt(password)
77
+ end
104
78
 
105
- # Mark my account as forgotten password.
106
- #
107
- # @example
108
- # user.forgot_password!
109
- def forgot_password!
110
- generate_confirmation_token
111
- save(:validate => false)
112
- end
79
+ # Set the remember token.
80
+ #
81
+ # @deprecated Use {#reset_remember_token!} instead
82
+ def remember_me!
83
+ warn "[DEPRECATION] remember_me!: use reset_remember_token! instead"
84
+ reset_remember_token!
85
+ end
113
86
 
114
- # Update my password.
115
- #
116
- # @param [String, String] password and password confirmation
117
- # @return [true, false] password was updated or not
118
- # @example
119
- # user.update_password('new-password', 'new-password')
120
- def update_password(new_password, new_password_confirmation)
121
- self.password_changing = true
122
- self.password = new_password
123
- self.password_confirmation = new_password_confirmation
124
- if valid?
125
- self.confirmation_token = nil
126
- generate_remember_token
127
- end
128
- save
129
- end
87
+ # Reset the remember token.
88
+ #
89
+ # @example
90
+ # user.reset_remember_token!
91
+ def reset_remember_token!
92
+ generate_remember_token
93
+ save(:validate => false)
94
+ end
130
95
 
131
- protected
96
+ # Mark my account as forgotten password.
97
+ #
98
+ # @example
99
+ # user.forgot_password!
100
+ def forgot_password!
101
+ generate_confirmation_token
102
+ save(:validate => false)
103
+ end
132
104
 
133
- def generate_hash(string)
134
- Digest::SHA1.hexdigest(string)
105
+ # Update my password.
106
+ #
107
+ # @return [true, false] password was updated or not
108
+ # @example
109
+ # user.update_password('new-password')
110
+ def update_password(new_password)
111
+ self.password_changing = true
112
+ self.password = new_password
113
+ if valid?
114
+ self.confirmation_token = nil
115
+ generate_remember_token
135
116
  end
117
+ save
118
+ end
136
119
 
137
- def encrypt(string)
138
- generate_hash("--#{salt}--#{string}--")
139
- end
120
+ protected
140
121
 
141
- def initialize_salt
142
- if salt.blank?
143
- self.salt = generate_hash("--#{Time.now.utc}--#{password}--#{rand}--")
144
- end
145
- end
122
+ def generate_hash(string)
123
+ Digest::SHA1.hexdigest(string)
124
+ end
146
125
 
147
- def encrypt_password
148
- if password.present?
149
- self.encrypted_password = encrypt(password)
150
- end
151
- end
126
+ def encrypt(string)
127
+ generate_hash("--#{salt}--#{string}--")
128
+ end
152
129
 
153
- def generate_remember_token
154
- self.remember_token = encrypt("--#{Time.now.utc}--#{encrypted_password}--#{id}--#{rand}--")
130
+ def initialize_salt
131
+ if salt.blank?
132
+ self.salt = ActiveSupport::SecureRandom.hex(20)
155
133
  end
134
+ end
156
135
 
157
- def generate_confirmation_token
158
- self.confirmation_token = encrypt("--#{Time.now.utc}--#{password}--#{rand}--")
136
+ def encrypt_password
137
+ if password.present?
138
+ self.encrypted_password = encrypt(password)
159
139
  end
140
+ end
160
141
 
161
- # Always false. Override to allow other forms of authentication
162
- # (username, facebook, etc).
163
- # @return [Boolean] true if the email field be left blank for this user
164
- def email_optional?
165
- false
166
- end
142
+ def generate_remember_token
143
+ self.remember_token = ActiveSupport::SecureRandom.hex(20)
144
+ end
167
145
 
168
- # True if the password has been set and the password is not being
169
- # updated and we are not updating the password. Override to allow
170
- # other forms of authentication (username, facebook, etc).
171
- # @return [Boolean] true if the password field can be left blank for this user
172
- def password_optional?
173
- encrypted_password.present? && password.blank? && password_changing.blank?
174
- end
146
+ def generate_confirmation_token
147
+ self.confirmation_token = ActiveSupport::SecureRandom.hex(20)
148
+ end
175
149
 
176
- def password_required?
177
- # warn "[DEPRECATION] password_required?: use !password_optional? instead"
178
- !password_optional?
179
- end
150
+ # Always false. Override to allow other forms of authentication
151
+ # (username, facebook, etc).
152
+ # @return [Boolean] true if the email field be left blank for this user
153
+ def email_optional?
154
+ false
155
+ end
180
156
 
181
- def downcase_email
182
- self.email = email.to_s.downcase
183
- end
157
+ # True if the password has been set and the password is not being
158
+ # updated and we are not updating the password. Override to allow
159
+ # other forms of authentication (username, facebook, etc).
160
+ # @return [Boolean] true if the password field can be left blank for this user
161
+ def password_optional?
162
+ encrypted_password.present? && password.blank? && password_changing.blank?
184
163
  end
185
164
 
186
- module ClassMethods
187
- # Authenticate with email and password.
188
- #
189
- # @param [String, String] email and password
190
- # @return [User, nil] authenticated user or nil
191
- # @example
192
- # User.authenticate("email@example.com", "password")
193
- def authenticate(email, password)
194
- return nil unless user = find_by_email(email.to_s.downcase)
195
- return user if user.authenticated?(password)
196
- end
165
+ def password_required?
166
+ # warn "[DEPRECATION] password_required?: use !password_optional? instead"
167
+ !password_optional?
197
168
  end
198
169
 
170
+ def downcase_email
171
+ self.email = email.to_s.downcase
172
+ end
199
173
  end
200
174
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  class ForgeriesController < ActionController::Base
4
4
  include Clearance::Authentication
5
5
  protect_from_forgery
6
- before_filter :authenticate
6
+ before_filter :authorize
7
7
 
8
8
  # This is off in test by default, but we need it for this test
9
9
  self.allow_forgery_protection = true
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Clearance::PasswordsController do
4
-
5
4
  include Shoulda::ActionMailer::Matchers
6
5
 
7
6
  it { should route(:get, '/users/1/password/edit').
@@ -101,18 +100,17 @@ describe Clearance::PasswordsController do
101
100
  it { should render_template(:new) }
102
101
  end
103
102
 
104
- describe "on PUT to #update with matching password and password confirmation" do
103
+ describe "on PUT to #update with password" do
105
104
  before do
106
105
  new_password = "new_password"
107
106
  @encrypted_new_password = @user.send(:encrypt, new_password)
108
107
  @user.encrypted_password.should_not == @encrypted_new_password
109
108
 
110
109
  put(:update,
111
- :user_id => @user,
112
- :token => @user.confirmation_token,
113
- :user => {
114
- :password => new_password,
115
- :password_confirmation => new_password
110
+ :user_id => @user,
111
+ :token => @user.confirmation_token,
112
+ :user => {
113
+ :password => new_password
116
114
  })
117
115
  @user.reload
118
116
  end
@@ -133,17 +131,13 @@ describe Clearance::PasswordsController do
133
131
  it { should redirect_to_url_after_update }
134
132
  end
135
133
 
136
- describe "on PUT to #update with password but blank password confirmation" do
134
+ describe "on PUT to #update with blank password" do
137
135
  before do
138
- new_password = "new_password"
139
- @encrypted_new_password = @user.send(:encrypt, new_password)
140
-
141
136
  put(:update,
142
137
  :user_id => @user.to_param,
143
138
  :token => @user.confirmation_token,
144
139
  :user => {
145
- :password => new_password,
146
- :password_confirmation => ''
140
+ :password => ''
147
141
  })
148
142
  @user.reload
149
143
  end
@@ -173,5 +167,4 @@ describe Clearance::PasswordsController do
173
167
  sign_in_as @user_one
174
168
  end
175
169
  end
176
-
177
170
  end
@@ -156,5 +156,4 @@ describe Clearance::SessionsController do
156
156
  @controller.current_user.should be_nil
157
157
  end
158
158
  end
159
-
160
159
  end
data/spec/factories.rb CHANGED
@@ -3,9 +3,8 @@ Factory.sequence :email do |n|
3
3
  end
4
4
 
5
5
  Factory.define :user do |user|
6
- user.email { Factory.next :email }
7
- user.password { "password" }
8
- user.password_confirmation { |instance| instance.password }
6
+ user.email { Factory.next :email }
7
+ user.password { "password" }
9
8
  end
10
9
 
11
10
  Factory.define :email_confirmed_user, :parent => :user do |user|
@@ -20,20 +20,6 @@ describe User do
20
20
  it { should_not allow_value("foo").for(:email) }
21
21
  it { should_not allow_value("example.com").for(:email) }
22
22
 
23
- it "should require password confirmation on create" do
24
- user = Factory.build(:user, :password => 'blah',
25
- :password_confirmation => 'boogidy')
26
- (user.save).should_not be
27
- user.errors[:password].should be_any
28
- end
29
-
30
- it "should require non blank password confirmation on create" do
31
- user = Factory.build(:user, :password => 'blah',
32
- :password_confirmation => '')
33
- (user.save).should_not be
34
- user.errors[:password].should be_any
35
- end
36
-
37
23
  it "should initialize salt" do
38
24
  Factory(:user).salt.should_not be_nil
39
25
  end
@@ -112,9 +98,9 @@ describe User do
112
98
  @old_encrypted_password = @user.encrypted_password
113
99
  end
114
100
 
115
- describe "who updates password with confirmation" do
101
+ describe "who updates password" do
116
102
  before do
117
- @user.update_password("new_password", "new_password")
103
+ @user.update_password("new_password")
118
104
  end
119
105
 
120
106
  it "should change encrypted password" do
@@ -126,12 +112,8 @@ describe User do
126
112
  it "should not generate the same remember token for users with the same password at the same time" do
127
113
  Time.stubs(:now => Time.now)
128
114
  password = 'secret'
129
- first_user = Factory(:user,
130
- :password => password,
131
- :password_confirmation => password)
132
- second_user = Factory(:user,
133
- :password => password,
134
- :password_confirmation => password)
115
+ first_user = Factory(:user, :password => password)
116
+ second_user = Factory(:user, :password => password)
135
117
 
136
118
  second_user.remember_token.should_not == first_user.remember_token
137
119
  end
@@ -155,9 +137,9 @@ describe User do
155
137
  end
156
138
 
157
139
  describe "and then updates password" do
158
- describe 'with confirmation' do
140
+ describe 'with password' do
159
141
  before do
160
- @user.update_password("new_password", "new_password")
142
+ @user.update_password("new_password")
161
143
  end
162
144
 
163
145
  it "should change encrypted password" do
@@ -169,23 +151,9 @@ describe User do
169
151
  end
170
152
  end
171
153
 
172
- describe 'without confirmation' do
173
- before do
174
- @user.update_password("new_password", "")
175
- end
176
-
177
- it "should not change encrypted password" do
178
- @old_encrypted_password.should == @user.encrypted_password
179
- end
180
-
181
- it "should not clear confirmation token" do
182
- @user.confirmation_token.should_not be_nil
183
- end
184
- end
185
-
186
- describe 'with blank password and confirmation' do
154
+ describe 'with blank password' do
187
155
  before do
188
- @user.update_password("", "")
156
+ @user.update_password("")
189
157
  end
190
158
 
191
159
  it "does not change encrypted password" do
@@ -251,7 +219,7 @@ describe User do
251
219
  end
252
220
 
253
221
  it "should initialize salt, generate remember token, and save encrypted password on update_password" do
254
- @user.update_password('password', 'password')
222
+ @user.update_password('password')
255
223
  @user.salt.should_not be_nil
256
224
  @user.encrypted_password.should_not be_nil
257
225
  @user.remember_token.should_not be_nil
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 10
8
- - 5
9
- version: 0.10.5
7
+ - 11
8
+ - 0
9
+ version: 0.11.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Dan Croak
@@ -31,7 +31,7 @@ autorequire:
31
31
  bindir: bin
32
32
  cert_chain: []
33
33
 
34
- date: 2011-04-19 00:00:00 -04:00
34
+ date: 2011-04-24 00:00:00 -04:00
35
35
  default_executable:
36
36
  dependencies:
37
37
  - !ruby/object:Gem::Dependency
@@ -94,7 +94,7 @@ dependencies:
94
94
  version: 0.10.0
95
95
  type: :development
96
96
  version_requirements: *id004
97
- description: Rails authentication with email & password.
97
+ description: Rails authentication & authorization with email & password.
98
98
  email: support@thoughtbot.com
99
99
  executables: []
100
100
 
@@ -124,7 +124,6 @@ files:
124
124
  - app/views/passwords/new.html.erb
125
125
  - app/views/sessions/new.html.erb
126
126
  - app/views/users/_form.html.erb
127
- - app/views/users/_inputs.html.erb
128
127
  - app/views/users/new.html.erb
129
128
  - clearance.gemspec
130
129
  - config/routes.rb
@@ -197,7 +196,7 @@ rubyforge_project:
197
196
  rubygems_version: 1.3.7
198
197
  signing_key:
199
198
  specification_version: 3
200
- summary: Rails authentication with email & password.
199
+ summary: Rails authentication & authorization with email & password.
201
200
  test_files:
202
201
  - features/engine/visitor_resets_password.feature
203
202
  - features/engine/visitor_signs_in.feature
@@ -1,6 +0,0 @@
1
- <%= form.inputs do %>
2
- <%= form.input :email %>
3
- <%= form.input :password %>
4
- <%= form.input :password_confirmation, :label => "Confirm password" %>
5
- <% end %>
6
-