clearance 0.16.3 → 1.0.0.rc1
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/.gitignore +1 -0
- data/.travis.yml +0 -2
- data/Appraisals +2 -2
- data/CONTRIBUTING.md +10 -19
- data/Gemfile +1 -1
- data/Gemfile.lock +81 -82
- data/NEWS.md +17 -4
- data/README.md +176 -113
- data/app/controllers/clearance/passwords_controller.rb +44 -31
- data/app/controllers/clearance/sessions_controller.rb +11 -10
- data/app/controllers/clearance/users_controller.rb +8 -12
- data/app/mailers/clearance_mailer.rb +4 -5
- data/app/views/clearance_mailer/change_password.html.erb +2 -4
- data/app/views/layouts/application.html.erb +7 -5
- data/app/views/passwords/edit.html.erb +8 -7
- data/app/views/passwords/new.html.erb +6 -5
- data/app/views/sessions/_form.html.erb +7 -5
- data/app/views/sessions/new.html.erb +3 -2
- data/app/views/users/_form.html.erb +4 -3
- data/clearance.gemspec +29 -27
- data/config/routes.rb +10 -13
- data/db/migrate/20110111224543_create_clearance_users.rb +18 -0
- data/db/schema.rb +4 -5
- data/features/engine/visitor_resets_password.feature +0 -7
- data/features/engine/visitor_signs_in.feature +7 -0
- data/features/engine/visitor_signs_up.feature +2 -2
- data/features/integration.feature +0 -1
- data/features/integration_with_test_unit.feature +43 -0
- data/features/step_definitions/configuration_steps.rb +8 -15
- data/features/step_definitions/engine/clearance_steps.rb +38 -38
- data/features/support/clearance.rb +1 -1
- data/features/support/env.rb +4 -21
- data/gemfiles/{3.0.12.gemfile → 3.0.15.gemfile} +1 -1
- data/gemfiles/{3.0.12.gemfile.lock → 3.0.15.gemfile.lock} +75 -76
- data/gemfiles/{3.2.3.gemfile → 3.1.6.gemfile} +1 -1
- data/gemfiles/{3.1.4.gemfile.lock → 3.1.6.gemfile.lock} +79 -80
- data/gemfiles/{3.1.4.gemfile → 3.2.6.gemfile} +1 -1
- data/gemfiles/{3.2.3.gemfile.lock → 3.2.6.gemfile.lock} +80 -81
- data/lib/clearance.rb +1 -0
- data/lib/clearance/authentication.rb +37 -69
- data/lib/clearance/configuration.rb +3 -18
- data/lib/clearance/constraints.rb +2 -0
- data/lib/clearance/constraints/signed_in.rb +28 -0
- data/lib/clearance/constraints/signed_out.rb +9 -0
- data/lib/clearance/engine.rb +4 -4
- data/lib/clearance/password_strategies.rb +5 -1
- data/lib/clearance/password_strategies/bcrypt.rb +27 -0
- data/lib/clearance/password_strategies/bcrypt_migration_from_sha1.rb +52 -0
- data/lib/clearance/password_strategies/blowfish.rb +11 -15
- data/lib/clearance/password_strategies/fake.rb +23 -0
- data/lib/clearance/password_strategies/sha1.rb +15 -21
- data/lib/clearance/session.rb +28 -20
- data/lib/clearance/testing.rb +8 -3
- data/lib/clearance/testing/assertion_error.rb +2 -7
- data/lib/clearance/testing/deny_access_matcher.rb +27 -32
- data/lib/clearance/testing/helpers.rb +7 -8
- data/lib/clearance/user.rb +26 -92
- data/lib/clearance/version.rb +1 -1
- data/lib/generators/clearance/install/templates/db/migrate/upgrade_clearance_to_diesel.rb +24 -26
- data/spec/clearance/constraints/signed_in_spec.rb +51 -0
- data/spec/clearance/constraints/signed_out_spec.rb +15 -0
- data/spec/clearance/rack_session_spec.rb +8 -7
- data/spec/clearance/session_spec.rb +28 -27
- data/spec/configuration_spec.rb +7 -6
- data/spec/controllers/denies_controller_spec.rb +11 -10
- data/spec/controllers/flashes_controller_spec.rb +5 -5
- data/spec/controllers/forgeries_controller_spec.rb +9 -9
- data/spec/controllers/passwords_controller_spec.rb +42 -55
- data/spec/controllers/sessions_controller_spec.rb +26 -33
- data/spec/controllers/users_controller_spec.rb +16 -14
- data/spec/factories.rb +1 -3
- data/spec/mailers/clearance_mailer_spec.rb +4 -4
- data/spec/models/bcrypt_migration_from_sha1_spec.rb +71 -0
- data/spec/models/bcrypt_spec.rb +40 -0
- data/spec/models/blowfish_spec.rb +14 -13
- data/spec/models/{clearance_user_spec.rb → password_strategies_spec.rb} +5 -5
- data/spec/models/sha1_spec.rb +18 -13
- data/spec/models/user_spec.rb +58 -73
- data/spec/spec_helper.rb +5 -6
- data/spec/support/clearance.rb +0 -4
- data/spec/support/cookies.rb +25 -27
- data/spec/support/request_with_remember_token.rb +19 -0
- metadata +95 -90
- data/db/migrate/20110111224543_create_diesel_clearance_users.rb +0 -19
- data/init.rb +0 -1
data/spec/models/sha1_spec.rb
CHANGED
@@ -3,41 +3,46 @@ require 'spec_helper'
|
|
3
3
|
describe Clearance::PasswordStrategies::SHA1 do
|
4
4
|
subject do
|
5
5
|
Class.new do
|
6
|
-
attr_accessor :salt, :
|
6
|
+
attr_accessor :salt, :encrypted_password
|
7
7
|
include Clearance::PasswordStrategies::SHA1
|
8
8
|
|
9
9
|
def generate_random_code; "code"; end
|
10
10
|
end.new
|
11
11
|
end
|
12
12
|
|
13
|
-
describe
|
14
|
-
context
|
15
|
-
let(:salt) {
|
16
|
-
let(:password) {
|
13
|
+
describe '#password=' do
|
14
|
+
context 'when the password is set' do
|
15
|
+
let(:salt) { 'salt' }
|
16
|
+
let(:password) { 'password' }
|
17
17
|
|
18
18
|
before do
|
19
19
|
subject.salt = salt
|
20
20
|
subject.password = password
|
21
|
-
subject.send(:encrypt_password)
|
22
21
|
end
|
23
22
|
|
24
|
-
it
|
25
|
-
|
23
|
+
it 'does not initialize the salt' do
|
24
|
+
subject.salt.should == salt
|
25
|
+
end
|
26
26
|
|
27
|
+
it 'encrypts the password using SHA1 and the existing salt' do
|
28
|
+
expected = Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
27
29
|
subject.encrypted_password.should == expected
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
|
-
context "when the
|
33
|
+
context "when the password is not set" do
|
32
34
|
before do
|
33
|
-
subject.salt
|
34
|
-
|
35
|
-
subject.send(:encrypt_password)
|
35
|
+
subject.salt = nil
|
36
|
+
subject.password = ""
|
36
37
|
end
|
37
38
|
|
38
|
-
it "
|
39
|
+
it "initializes the salt" do
|
39
40
|
subject.salt.should_not be_nil
|
40
41
|
end
|
42
|
+
|
43
|
+
it "doesn't encrpt the password" do
|
44
|
+
subject.encrypted_password.should be_nil
|
45
|
+
end
|
41
46
|
end
|
42
47
|
end
|
43
48
|
end
|
data/spec/models/user_spec.rb
CHANGED
@@ -4,129 +4,131 @@ describe User do
|
|
4
4
|
it { should have_db_index(:email) }
|
5
5
|
it { should have_db_index(:remember_token) }
|
6
6
|
|
7
|
-
describe
|
7
|
+
describe 'when signing up' do
|
8
8
|
it { should validate_presence_of(:email) }
|
9
9
|
it { should validate_presence_of(:password) }
|
10
|
-
it { should allow_value(
|
11
|
-
it { should allow_value(
|
12
|
-
it { should_not allow_value(
|
13
|
-
it { should_not allow_value(
|
14
|
-
it { should_not allow_value(
|
15
|
-
it { should_not allow_value(
|
16
|
-
it { should_not allow_value(
|
17
|
-
|
18
|
-
it
|
19
|
-
user = create(:user, :email =>
|
20
|
-
user.email.should ==
|
10
|
+
it { should allow_value('foo@example.co.uk').for(:email) }
|
11
|
+
it { should allow_value('foo@example.com').for(:email) }
|
12
|
+
it { should_not allow_value('foo@').for(:email) }
|
13
|
+
it { should_not allow_value('foo@example..com').for(:email) }
|
14
|
+
it { should_not allow_value('foo@.example.com').for(:email) }
|
15
|
+
it { should_not allow_value('foo').for(:email) }
|
16
|
+
it { should_not allow_value('example.com').for(:email) }
|
17
|
+
|
18
|
+
it 'stores email in down case' do
|
19
|
+
user = create(:user, :email => 'John.Doe@example.com')
|
20
|
+
user.email.should == 'john.doe@example.com'
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
describe
|
24
|
+
describe 'when multiple users have signed up' do
|
25
25
|
before { create(:user) }
|
26
26
|
it { should validate_uniqueness_of(:email) }
|
27
27
|
end
|
28
28
|
|
29
|
-
describe
|
29
|
+
describe 'a user' do
|
30
30
|
before do
|
31
|
-
@user
|
31
|
+
@user = create(:user)
|
32
32
|
@password = @user.password
|
33
33
|
end
|
34
34
|
|
35
|
-
it
|
36
|
-
(Clearance.configuration.user_model.authenticate(@user.email, @password)).
|
35
|
+
it 'is authenticated with correct email and password' do
|
36
|
+
(Clearance.configuration.user_model.authenticate(@user.email, @password)).
|
37
|
+
should be
|
37
38
|
@user.should be_authenticated(@password)
|
38
39
|
end
|
39
40
|
|
40
|
-
it
|
41
|
-
(Clearance.configuration.user_model.authenticate(@user.email.upcase, @password)).
|
41
|
+
it 'is authenticated with correct uppercased email and correct password' do
|
42
|
+
(Clearance.configuration.user_model.authenticate(@user.email.upcase, @password)).
|
43
|
+
should be
|
42
44
|
@user.should be_authenticated(@password)
|
43
45
|
end
|
44
46
|
|
45
|
-
it
|
46
|
-
(Clearance.configuration.user_model.authenticate(@user.email, 'bad_password')).
|
47
|
+
it 'is authenticated with incorrect credentials' do
|
48
|
+
(Clearance.configuration.user_model.authenticate(@user.email, 'bad_password')).
|
49
|
+
should_not be
|
47
50
|
@user.should_not be_authenticated('bad password')
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
51
|
-
describe
|
54
|
+
describe 'when resetting authentication with reset_remember_token!' do
|
52
55
|
before do
|
53
56
|
@user = create(:user)
|
54
|
-
@user.remember_token =
|
57
|
+
@user.remember_token = 'old-token'
|
55
58
|
@user.reset_remember_token!
|
56
59
|
end
|
57
60
|
|
58
|
-
it
|
59
|
-
@user.remember_token.should_not ==
|
61
|
+
it 'changes the remember token' do
|
62
|
+
@user.remember_token.should_not == 'old-token'
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
63
|
-
describe
|
66
|
+
describe 'an email confirmed user' do
|
64
67
|
before do
|
65
68
|
@user = create(:user)
|
66
69
|
@old_encrypted_password = @user.encrypted_password
|
67
70
|
end
|
68
71
|
|
69
|
-
describe
|
72
|
+
describe 'who updates password' do
|
70
73
|
before do
|
71
|
-
@user.update_password(
|
74
|
+
@user.update_password('new_password')
|
72
75
|
end
|
73
76
|
|
74
|
-
it
|
77
|
+
it 'changes encrypted password' do
|
75
78
|
@user.encrypted_password.should_not == @old_encrypted_password
|
76
79
|
end
|
77
80
|
end
|
78
81
|
end
|
79
82
|
|
80
|
-
it
|
81
|
-
Time.stubs
|
82
|
-
password
|
83
|
-
first_user
|
83
|
+
it 'does not generate same remember token for users with same password at same time' do
|
84
|
+
Time.stubs :now => Time.now
|
85
|
+
password = 'secret'
|
86
|
+
first_user = create(:user, :password => password)
|
84
87
|
second_user = create(:user, :password => password)
|
85
|
-
|
86
88
|
second_user.remember_token.should_not == first_user.remember_token
|
87
89
|
end
|
88
90
|
|
89
|
-
describe
|
91
|
+
describe 'a user' do
|
90
92
|
before do
|
91
93
|
@user = create(:user)
|
92
94
|
@old_encrypted_password = @user.encrypted_password
|
93
95
|
end
|
94
96
|
|
95
|
-
describe
|
97
|
+
describe 'who requests password reminder' do
|
96
98
|
before do
|
97
99
|
@user.confirmation_token.should be_nil
|
98
100
|
@user.forgot_password!
|
99
101
|
end
|
100
102
|
|
101
|
-
it
|
103
|
+
it 'generates confirmation token' do
|
102
104
|
@user.confirmation_token.should_not be_nil
|
103
105
|
end
|
104
106
|
|
105
|
-
describe
|
107
|
+
describe 'and then updates password' do
|
106
108
|
describe 'with password' do
|
107
109
|
before do
|
108
|
-
@user.update_password
|
110
|
+
@user.update_password 'new_password'
|
109
111
|
end
|
110
112
|
|
111
|
-
it
|
113
|
+
it 'changes encrypted password' do
|
112
114
|
@user.encrypted_password.should_not == @old_encrypted_password
|
113
115
|
end
|
114
116
|
|
115
|
-
it
|
117
|
+
it 'clears confirmation token' do
|
116
118
|
@user.confirmation_token.should be_nil
|
117
119
|
end
|
118
120
|
end
|
119
121
|
|
120
122
|
describe 'with blank password' do
|
121
123
|
before do
|
122
|
-
@user.update_password
|
124
|
+
@user.update_password ''
|
123
125
|
end
|
124
126
|
|
125
|
-
it
|
127
|
+
it 'does not change encrypted password' do
|
126
128
|
@user.encrypted_password.should == @old_encrypted_password
|
127
129
|
end
|
128
130
|
|
129
|
-
it
|
131
|
+
it 'does not clear confirmation token' do
|
130
132
|
@user.confirmation_token.should_not be_nil
|
131
133
|
end
|
132
134
|
end
|
@@ -134,7 +136,7 @@ describe User do
|
|
134
136
|
end
|
135
137
|
end
|
136
138
|
|
137
|
-
describe
|
139
|
+
describe 'a user with an optional email' do
|
138
140
|
before do
|
139
141
|
@user = User.new
|
140
142
|
class << @user
|
@@ -147,12 +149,13 @@ describe User do
|
|
147
149
|
subject { @user }
|
148
150
|
|
149
151
|
it { should allow_value(nil).for(:email) }
|
150
|
-
it { should allow_value(
|
152
|
+
it { should allow_value('').for(:email) }
|
151
153
|
end
|
152
154
|
|
153
|
-
describe
|
155
|
+
describe 'a user with an optional password' do
|
154
156
|
before do
|
155
157
|
@user = User.new
|
158
|
+
|
156
159
|
class << @user
|
157
160
|
def password_optional?
|
158
161
|
true
|
@@ -163,42 +166,24 @@ describe User do
|
|
163
166
|
subject { @user }
|
164
167
|
|
165
168
|
it { should allow_value(nil).for(:password) }
|
166
|
-
it { should allow_value(
|
167
|
-
end
|
168
|
-
|
169
|
-
describe "user factory" do
|
170
|
-
it "should create a valid user with just an overridden password" do
|
171
|
-
build(:user, :password => "test").should be_valid
|
172
|
-
end
|
169
|
+
it { should allow_value('').for(:password) }
|
173
170
|
end
|
174
171
|
|
175
|
-
describe
|
176
|
-
|
177
|
-
|
178
|
-
sql = "update users set salt = NULL, encrypted_password = NULL, remember_token = NULL where id = #{@user.id}"
|
179
|
-
ActiveRecord::Base.connection.update(sql)
|
180
|
-
@user.reload.salt.should be_nil
|
181
|
-
@user.reload.encrypted_password.should be_nil
|
182
|
-
@user.reload.remember_token.should be_nil
|
183
|
-
end
|
184
|
-
|
185
|
-
it "should initialize salt, generate remember token, and save encrypted password on update_password" do
|
186
|
-
@user.update_password('password')
|
187
|
-
@user.salt.should_not be_nil
|
188
|
-
@user.encrypted_password.should_not be_nil
|
189
|
-
@user.remember_token.should_not be_nil
|
172
|
+
describe 'user factory' do
|
173
|
+
it 'should create a valid user with just an overridden password' do
|
174
|
+
build(:user, :password => 'test').should be_valid
|
190
175
|
end
|
191
176
|
end
|
192
177
|
|
193
|
-
describe
|
194
|
-
let(:password) {
|
178
|
+
describe 'the password setter on a User' do
|
179
|
+
let(:password) { 'a-password' }
|
195
180
|
before { subject.send(:password=, password) }
|
196
181
|
|
197
|
-
it
|
182
|
+
it 'sets password to the plain-text password' do
|
198
183
|
subject.password.should == password
|
199
184
|
end
|
200
185
|
|
201
|
-
it
|
186
|
+
it 'also sets encrypted_password' do
|
202
187
|
subject.encrypted_password.should_not be_nil
|
203
188
|
end
|
204
189
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
ENV[
|
1
|
+
ENV['RAILS_ENV'] ||= 'test'
|
2
2
|
|
3
|
-
PROJECT_ROOT = File.expand_path(
|
4
|
-
$LOAD_PATH << File.join(PROJECT_ROOT,
|
3
|
+
PROJECT_ROOT = File.expand_path('../..', __FILE__)
|
4
|
+
$LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
|
5
5
|
|
6
6
|
require 'rails/all'
|
7
7
|
require 'rails/test_help'
|
@@ -14,13 +14,12 @@ require 'bourne'
|
|
14
14
|
require 'timecop'
|
15
15
|
require 'factory_girl_rails'
|
16
16
|
require 'shoulda-matchers'
|
17
|
-
|
18
17
|
require 'clearance/testing'
|
19
18
|
|
20
|
-
Dir[Rails.root.join(
|
19
|
+
Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f}
|
21
20
|
|
22
21
|
RSpec.configure do |config|
|
22
|
+
config.include FactoryGirl::Syntax::Methods
|
23
23
|
config.mock_with :mocha
|
24
24
|
config.use_transactional_fixtures = true
|
25
|
-
config.include FactoryGirl::Syntax::Methods
|
26
25
|
end
|
data/spec/support/clearance.rb
CHANGED
data/spec/support/cookies.rb
CHANGED
@@ -1,21 +1,40 @@
|
|
1
1
|
RSpec::Matchers.define :set_cookie do |name, expected_value, expected_expires_at|
|
2
|
+
failure_message_for_should do
|
3
|
+
"Expected #{expectation} got #{result}"
|
4
|
+
end
|
5
|
+
|
2
6
|
match do |subject|
|
3
7
|
@headers = subject
|
4
8
|
@expected_name = name
|
5
9
|
@expected_value = expected_value
|
6
10
|
@expected_expires_at = expected_expires_at
|
7
|
-
|
8
11
|
extract_cookies
|
9
12
|
find_expected_cookie
|
10
13
|
parse_expiration
|
11
14
|
parse_value
|
12
15
|
parse_path
|
13
|
-
|
14
16
|
ensure_cookie_set
|
15
17
|
ensure_expiration_correct
|
16
18
|
ensure_path_is_correct
|
17
19
|
end
|
18
20
|
|
21
|
+
def ensure_cookie_set
|
22
|
+
@value.should == @expected_value
|
23
|
+
end
|
24
|
+
|
25
|
+
def ensure_expiration_correct
|
26
|
+
@expires_at.should_not be_nil
|
27
|
+
@expires_at.should be_within(100).of(@expected_expires_at)
|
28
|
+
end
|
29
|
+
|
30
|
+
def ensure_path_is_correct
|
31
|
+
@path.should == "/"
|
32
|
+
end
|
33
|
+
|
34
|
+
def expectation
|
35
|
+
"a cookie named #{@expected_name} with value #{@expected_value.inspect} expiring at #{@expected_expires_at.inspect}"
|
36
|
+
end
|
37
|
+
|
19
38
|
def extract_cookies
|
20
39
|
@cookie_headers = @headers['Set-Cookie'] || []
|
21
40
|
@cookie_headers = [@cookie_headers] if @cookie_headers.respond_to?(:to_str)
|
@@ -33,37 +52,16 @@ RSpec::Matchers.define :set_cookie do |name, expected_value, expected_expires_at
|
|
33
52
|
end
|
34
53
|
end
|
35
54
|
|
36
|
-
def parse_value
|
37
|
-
if @cookie && result = @cookie.match(/=(.*?)(?:;|$)/)
|
38
|
-
@value = result[1]
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
55
|
def parse_path
|
43
56
|
if @cookie && result = @cookie.match(/; path=(.*?)(;|$)/)
|
44
57
|
@path = result[1]
|
45
58
|
end
|
46
59
|
end
|
47
60
|
|
48
|
-
def
|
49
|
-
@
|
50
|
-
|
51
|
-
|
52
|
-
def ensure_expiration_correct
|
53
|
-
@expires_at.should_not be_nil
|
54
|
-
@expires_at.should be_within(100).of(@expected_expires_at)
|
55
|
-
end
|
56
|
-
|
57
|
-
def ensure_path_is_correct
|
58
|
-
@path.should == "/"
|
59
|
-
end
|
60
|
-
|
61
|
-
failure_message_for_should do
|
62
|
-
"Expected #{expectation} got #{result}"
|
63
|
-
end
|
64
|
-
|
65
|
-
def expectation
|
66
|
-
"a cookie named #{@expected_name} with value #{@expected_value.inspect} expiring at #{@expected_expires_at.inspect}"
|
61
|
+
def parse_value
|
62
|
+
if @cookie && result = @cookie.match(/=(.*?)(?:;|$)/)
|
63
|
+
@value = result[1]
|
64
|
+
end
|
67
65
|
end
|
68
66
|
|
69
67
|
def result
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RememberTokenHelpers
|
2
|
+
def request_with_remember_token(remember_token)
|
3
|
+
cookies = {
|
4
|
+
'action_dispatch.cookies' => {
|
5
|
+
Clearance::Session::REMEMBER_TOKEN_COOKIE => remember_token
|
6
|
+
}
|
7
|
+
}
|
8
|
+
env = { :clearance => Clearance::Session.new(cookies) }
|
9
|
+
Rack::Request.new env
|
10
|
+
end
|
11
|
+
|
12
|
+
def request_without_remember_token
|
13
|
+
request_with_remember_token nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.include RememberTokenHelpers
|
19
|
+
end
|