thoughtbot-clearance 0.4.4 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.textile +11 -0
- data/README.textile +14 -10
- data/Rakefile +1 -1
- data/generators/clearance_features/clearance_features_generator.rb +2 -1
- data/generators/clearance_features/templates/features/password_reset.feature +1 -1
- data/generators/clearance_features/templates/features/sign_in.feature +2 -2
- data/generators/clearance_features/templates/features/step_definitions/clearance_steps.rb +0 -3
- data/lib/clearance/app/controllers/application_controller.rb +3 -4
- data/lib/clearance/app/models/user.rb +4 -8
- data/lib/clearance/test/test_helper.rb +0 -2
- data/lib/clearance/test/unit/user_test.rb +14 -15
- data/shoulda_macros/clearance.rb +0 -4
- metadata +2 -3
- data/TODO.textile +0 -8
data/CHANGELOG.textile
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
h2. 0.4.5 (unreleased)
|
2
|
+
|
3
|
+
* [#43] Removed email downcasing. (local-part is case sensitive per RFC5321)
|
4
|
+
* [#42] Removed dependency on Mocha.
|
5
|
+
* Required Shoulda >= 2.9.1.
|
6
|
+
* Added password reset feature to clearance_features generator.
|
7
|
+
* Removed unnecessary session[:salt].
|
8
|
+
* [#41] Only store location for session[:return_to] for GET requests.
|
9
|
+
* Audited "sign up" naming convention. "Register" had slipped in a few places.
|
10
|
+
* 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.
|
11
|
+
|
1
12
|
h2. 0.4.4 (2/2/2009)
|
2
13
|
|
3
14
|
* Added a generator for Cucumber features
|
data/README.textile
CHANGED
@@ -12,24 +12,28 @@ h2. Gem installation (Rails 2.1+)
|
|
12
12
|
|
13
13
|
In config/environment.rb:
|
14
14
|
|
15
|
-
config.gem
|
15
|
+
config.gem "thoughtbot-clearance",
|
16
|
+
:lib => 'clearance',
|
17
|
+
:source => 'http://gems.github.com',
|
18
|
+
:version => '>= 0.4.3'
|
19
|
+
|
20
|
+
In config/environments/test.rb:
|
21
|
+
|
16
22
|
config.gem 'thoughtbot-shoulda',
|
17
23
|
:lib => 'shoulda',
|
18
24
|
:source => "http://gems.github.com",
|
19
|
-
:version => '>= 2.
|
25
|
+
:version => '>= 2.9.1'
|
20
26
|
config.gem 'thoughtbot-factory_girl',
|
21
27
|
:lib => 'factory_girl',
|
22
28
|
:source => "http://gems.github.com",
|
23
29
|
:version => '>= 1.1.5'
|
24
|
-
config.gem "thoughtbot-clearance",
|
25
|
-
:lib => 'clearance',
|
26
|
-
:source => 'http://gems.github.com',
|
27
|
-
:version => '>= 0.3.9'
|
28
30
|
|
29
31
|
Then:
|
30
32
|
|
31
33
|
rake gems:install
|
32
|
-
rake gems:unpack
|
34
|
+
rake gems:unpack
|
35
|
+
rake gems:install RAILS_ENV=test
|
36
|
+
rake gems:unpack RAILS_ENV=test
|
33
37
|
|
34
38
|
h2. The generator
|
35
39
|
|
@@ -93,7 +97,7 @@ In config/environment.rb:
|
|
93
97
|
|
94
98
|
h2. Tests
|
95
99
|
|
96
|
-
The tests use "Shoulda":http://thoughtbot.com/projects/shoulda >= 2.
|
100
|
+
The tests use "Shoulda":http://thoughtbot.com/projects/shoulda >= 2.9.1 and "Factory Girl":http://thoughtbot.com/projects/factory_girl >= 1.1.5. There needs to be a Clearance module in your test/test_helper.rb:
|
97
101
|
|
98
102
|
class Test::Unit::TestCase
|
99
103
|
self.use_transactional_fixtures = true
|
@@ -108,7 +112,7 @@ h2. Usage: basic workflow
|
|
108
112
|
|
109
113
|
Rails authentication with Clearance uses the standard approach thoughtbot and our clients have agreed upon.
|
110
114
|
|
111
|
-
Users
|
115
|
+
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).
|
112
116
|
|
113
117
|
Registered users can sign in and out (SessionsController). If they forget their password, they request an email (ClearanceMailer) containing a link to change it (PasswordsController).
|
114
118
|
|
@@ -169,7 +173,7 @@ Actions that redirect (create, update, and destroy) in Clearance controllers are
|
|
169
173
|
|
170
174
|
There are similar methods in other controllers as well:
|
171
175
|
|
172
|
-
UsersController#url_after_create (
|
176
|
+
UsersController#url_after_create (sign up)
|
173
177
|
SessionsController#url_after_create (sign in)
|
174
178
|
SessionsController#url_after_destroy (sign out)
|
175
179
|
PasswordsController#url_after_create (password request)
|
data/Rakefile
CHANGED
@@ -50,7 +50,7 @@ task :default => ['test:all', 'test:features']
|
|
50
50
|
|
51
51
|
gem_spec = Gem::Specification.new do |gem_spec|
|
52
52
|
gem_spec.name = "clearance"
|
53
|
-
gem_spec.version = "0.4.
|
53
|
+
gem_spec.version = "0.4.5"
|
54
54
|
gem_spec.summary = "Rails authentication for developers who write tests."
|
55
55
|
gem_spec.email = "support@thoughtbot.com"
|
56
56
|
gem_spec.homepage = "http://github.com/thoughtbot/clearance"
|
@@ -7,7 +7,8 @@ class ClearanceFeaturesGenerator < Rails::Generator::Base
|
|
7
7
|
["features/step_definitions/clearance_steps.rb",
|
8
8
|
"features/sign_in.feature",
|
9
9
|
"features/sign_out.feature",
|
10
|
-
"features/sign_up.feature"
|
10
|
+
"features/sign_up.feature",
|
11
|
+
"features/password_reset.feature"].each do |file|
|
11
12
|
m.file file, file
|
12
13
|
end
|
13
14
|
end
|
@@ -3,7 +3,7 @@ Fature: Password Reset
|
|
3
3
|
A user
|
4
4
|
Should be able to reset it
|
5
5
|
|
6
|
-
Scenario: User is not
|
6
|
+
Scenario: User is not signed up
|
7
7
|
Given there is no user with "email@person.com"
|
8
8
|
When I request password reset link to be sent to "email@person.com"
|
9
9
|
Then I should see "Unknown email"
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Feature: Sign in
|
2
2
|
In order to get access to protected sections of the site
|
3
|
-
A
|
3
|
+
A user
|
4
4
|
Should be able to sign in
|
5
5
|
|
6
|
-
Scenario User is not
|
6
|
+
Scenario User is not signed up
|
7
7
|
Given there is no user with "email@person.com"
|
8
8
|
When I go to the sign in page
|
9
9
|
And I sign in as "email@person.com/password"
|
@@ -28,17 +28,14 @@ end
|
|
28
28
|
|
29
29
|
Then /^I should be signed in$/ do
|
30
30
|
assert_not_nil request.session[:user_id]
|
31
|
-
assert_not_nil request.session[:salt]
|
32
31
|
end
|
33
32
|
|
34
33
|
Then /^I should not be signed in$/ do
|
35
34
|
assert_nil request.session[:user_id]
|
36
|
-
assert_nil request.session[:salt]
|
37
35
|
end
|
38
36
|
|
39
37
|
When /^session is cleared$/ do
|
40
38
|
request.session[:user_id] = nil
|
41
|
-
request.session[:salt] = nil
|
42
39
|
end
|
43
40
|
|
44
41
|
# Emails
|
@@ -26,8 +26,8 @@ module Clearance
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def user_from_session
|
29
|
-
if session[:user_id]
|
30
|
-
user = User.
|
29
|
+
if session[:user_id]
|
30
|
+
user = User.find_by_id(session[:user_id])
|
31
31
|
user && user.email_confirmed? ? user : nil
|
32
32
|
end
|
33
33
|
end
|
@@ -47,7 +47,6 @@ module Clearance
|
|
47
47
|
def sign_in(user)
|
48
48
|
if user
|
49
49
|
session[:user_id] = user.id
|
50
|
-
session[:salt] = user.salt
|
51
50
|
end
|
52
51
|
end
|
53
52
|
|
@@ -66,7 +65,7 @@ module Clearance
|
|
66
65
|
end
|
67
66
|
|
68
67
|
def store_location
|
69
|
-
session[:return_to] = request.request_uri
|
68
|
+
session[:return_to] = request.request_uri if request.get?
|
70
69
|
end
|
71
70
|
|
72
71
|
def deny_access(flash_message = nil, opts = {})
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'digest/
|
1
|
+
require 'digest/sha1'
|
2
2
|
|
3
3
|
module Clearance
|
4
4
|
module App
|
@@ -17,10 +17,10 @@ module Clearance
|
|
17
17
|
validates_uniqueness_of :email, :case_sensitive => false
|
18
18
|
validates_format_of :email, :with => %r{.+@.+\..+}
|
19
19
|
|
20
|
-
before_save :initialize_salt, :encrypt_password, :initialize_token
|
20
|
+
before_save :initialize_salt, :encrypt_password, :initialize_token
|
21
21
|
|
22
22
|
def self.authenticate(email, password)
|
23
|
-
user = find(:first, :conditions => ['
|
23
|
+
user = find(:first, :conditions => ['email = ?', email.to_s])
|
24
24
|
user && user.authenticated?(password) ? user : nil
|
25
25
|
end
|
26
26
|
|
@@ -72,7 +72,7 @@ module Clearance
|
|
72
72
|
protected
|
73
73
|
|
74
74
|
def generate_hash(string)
|
75
|
-
Digest::
|
75
|
+
Digest::SHA1.hexdigest(string)
|
76
76
|
end
|
77
77
|
|
78
78
|
def initialize_salt
|
@@ -104,10 +104,6 @@ module Clearance
|
|
104
104
|
encrypted_password.blank? || !password.blank?
|
105
105
|
end
|
106
106
|
|
107
|
-
def downcase_email
|
108
|
-
self.email = email.to_s.downcase
|
109
|
-
end
|
110
|
-
|
111
107
|
end
|
112
108
|
end
|
113
109
|
|
@@ -11,13 +11,11 @@ module Clearance
|
|
11
11
|
user.confirm_email!
|
12
12
|
end
|
13
13
|
@request.session[:user_id] = user.id
|
14
|
-
@request.session[:salt] = user.salt
|
15
14
|
return user
|
16
15
|
end
|
17
16
|
|
18
17
|
def sign_out
|
19
18
|
@request.session[:user_id] = nil
|
20
|
-
@request.session[:salt] = nil
|
21
19
|
end
|
22
20
|
|
23
21
|
end
|
@@ -6,14 +6,14 @@ module Clearance
|
|
6
6
|
def self.included(unit_test)
|
7
7
|
unit_test.class_eval do
|
8
8
|
|
9
|
-
|
9
|
+
should_not_allow_mass_assignment_of :email_confirmed,
|
10
10
|
:salt, :encrypted_password,
|
11
11
|
:token, :token_expires_at
|
12
12
|
|
13
13
|
# signing up
|
14
14
|
|
15
15
|
context "When signing up" do
|
16
|
-
|
16
|
+
should_validate_presence_of :email, :password
|
17
17
|
should_allow_values_for :email, "foo@example.com"
|
18
18
|
should_not_allow_values_for :email, "foo"
|
19
19
|
should_not_allow_values_for :email, "example.com"
|
@@ -33,13 +33,13 @@ module Clearance
|
|
33
33
|
context "encrypt password" do
|
34
34
|
setup do
|
35
35
|
@salt = "salt"
|
36
|
-
|
37
|
-
|
38
|
-
@user
|
36
|
+
@user = Factory.build(:user, :salt => @salt)
|
37
|
+
def @user.initialize_salt; end
|
38
|
+
@user.save!
|
39
39
|
@password = @user.password
|
40
40
|
|
41
41
|
@user.encrypt(@password)
|
42
|
-
@expected = Digest::
|
42
|
+
@expected = Digest::SHA1.hexdigest("--#{@salt}--#{@password}--")
|
43
43
|
end
|
44
44
|
|
45
45
|
should "create an encrypted password using SHA512 encryption" do
|
@@ -48,16 +48,16 @@ module Clearance
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
should "store email in
|
51
|
+
should "store email in exact case" do
|
52
52
|
user = Factory(:user, :email => "John.Doe@example.com")
|
53
|
-
assert_equal "
|
53
|
+
assert_equal "John.Doe@example.com", user.email
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
57
|
context "When multiple users have signed up" do
|
58
58
|
setup { @user = Factory(:user) }
|
59
59
|
|
60
|
-
|
60
|
+
should_validate_uniqueness_of :email
|
61
61
|
end
|
62
62
|
|
63
63
|
# confirming email
|
@@ -97,11 +97,6 @@ module Clearance
|
|
97
97
|
assert @user.authenticated?(@password)
|
98
98
|
end
|
99
99
|
|
100
|
-
should "authenticate with good credentials, email in uppercase" do
|
101
|
-
assert User.authenticate(@user.email.upcase, @password)
|
102
|
-
assert @user.authenticated?(@password)
|
103
|
-
end
|
104
|
-
|
105
100
|
should "not authenticate with bad credentials" do
|
106
101
|
assert ! User.authenticate(@user.email, 'horribly_wrong_password')
|
107
102
|
assert ! @user.authenticated?('horribly_wrong_password')
|
@@ -185,6 +180,7 @@ module Clearance
|
|
185
180
|
assert_nil @user.token
|
186
181
|
@user.forgot_password!
|
187
182
|
end
|
183
|
+
|
188
184
|
should "generate token" do
|
189
185
|
assert_not_nil @user.token
|
190
186
|
end
|
@@ -199,17 +195,20 @@ module Clearance
|
|
199
195
|
end
|
200
196
|
|
201
197
|
should_change "@user.encrypted_password"
|
198
|
+
|
202
199
|
should "clear token" do
|
203
200
|
assert_nil @user.token
|
204
201
|
end
|
205
202
|
end
|
203
|
+
|
206
204
|
context 'with a password without a confirmation' do
|
207
205
|
setup do
|
208
206
|
@user.update_password(
|
209
207
|
:password => "new_password",
|
210
208
|
:password_confirmation => ""
|
211
209
|
)
|
212
|
-
end
|
210
|
+
end
|
211
|
+
|
213
212
|
should "not clear token" do
|
214
213
|
assert_not_nil @user.token
|
215
214
|
end
|
data/shoulda_macros/clearance.rb
CHANGED
@@ -10,8 +10,6 @@ module Clearance
|
|
10
10
|
"please pass a User. try: should_be_signed_in_as { @user }"
|
11
11
|
assert_equal user.id, session[:user_id],
|
12
12
|
"session[:user_id] is not set to User's id"
|
13
|
-
assert_equal user.salt, session[:salt],
|
14
|
-
"session[:salt] is not set to User's salt"
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
@@ -30,7 +28,6 @@ module Clearance
|
|
30
28
|
def should_not_be_signed_in
|
31
29
|
should "not be signed in" do
|
32
30
|
assert_nil session[:user_id]
|
33
|
-
assert_nil session[:salt]
|
34
31
|
end
|
35
32
|
end
|
36
33
|
|
@@ -167,7 +164,6 @@ module Clearance
|
|
167
164
|
end
|
168
165
|
end
|
169
166
|
|
170
|
-
|
171
167
|
# FORMS
|
172
168
|
|
173
169
|
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.
|
4
|
+
version: 0.4.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thoughtbot, inc.
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2009-02-
|
18
|
+
date: 2009-02-08 21:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -32,7 +32,6 @@ files:
|
|
32
32
|
- LICENSE
|
33
33
|
- Rakefile
|
34
34
|
- README.textile
|
35
|
-
- TODO.textile
|
36
35
|
- generators/clearance
|
37
36
|
- generators/clearance/clearance_generator.rb
|
38
37
|
- generators/clearance/lib
|
data/TODO.textile
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
(highest priority first)
|
2
|
-
|
3
|
-
# refactor password controller test
|
4
|
-
# existing_user? methods ... if salt is wrong, user may not be found b/c of invalid credentials. is :not_found the correct code to return in that use case? if not, method probably needs to be split into another conditional.
|
5
|
-
# document shoulda macros
|
6
|
-
# will SHA512 hashes fit in all the places they are being used? (db columns - fit now, sessions) 128 characters
|
7
|
-
|
8
|
-
http://adam.speaksoutofturn.com/post/57615195/entication-vs-orization
|