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
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Clearance::SessionsController do
|
4
|
-
describe
|
4
|
+
describe 'on GET to /sessions/new' do
|
5
5
|
before { get :new }
|
6
6
|
|
7
7
|
it { should respond_with(:success) }
|
@@ -9,95 +9,88 @@ describe Clearance::SessionsController do
|
|
9
9
|
it { should_not set_the_flash }
|
10
10
|
end
|
11
11
|
|
12
|
-
describe
|
12
|
+
describe 'on POST to #create with good credentials' do
|
13
13
|
before do
|
14
14
|
@user = create(:user)
|
15
|
-
@user.update_attribute
|
16
|
-
post :create, :session => {
|
17
|
-
:email => @user.email,
|
18
|
-
:password => @user.password }
|
15
|
+
@user.update_attribute :remember_token, 'old-token'
|
16
|
+
post :create, :session => { :email => @user.email, :password => @user.password }
|
19
17
|
end
|
20
18
|
|
21
19
|
it { should redirect_to_url_after_create }
|
22
20
|
|
23
|
-
it
|
21
|
+
it 'sets the user in the clearance session' do
|
24
22
|
controller.current_user.should == @user
|
25
23
|
end
|
26
24
|
|
27
|
-
it
|
28
|
-
@user.reload.remember_token.should ==
|
25
|
+
it 'should not change the remember token' do
|
26
|
+
@user.reload.remember_token.should == 'old-token'
|
29
27
|
end
|
30
28
|
end
|
31
29
|
|
32
|
-
describe
|
30
|
+
describe 'on POST to #create with good credentials and a session return url' do
|
33
31
|
before do
|
34
32
|
@user = create(:user)
|
35
33
|
@return_url = '/url_in_the_session'
|
36
34
|
@request.session[:return_to] = @return_url
|
37
|
-
post :create, :session => {
|
38
|
-
:email => @user.email,
|
39
|
-
:password => @user.password }
|
35
|
+
post :create, :session => { :email => @user.email, :password => @user.password }
|
40
36
|
end
|
41
37
|
|
42
|
-
it
|
38
|
+
it 'redirects to the return URL' do
|
43
39
|
should redirect_to(@return_url)
|
44
40
|
end
|
45
41
|
end
|
46
42
|
|
47
|
-
describe
|
43
|
+
describe 'on POST to #create with good credentials and a request return url' do
|
48
44
|
before do
|
49
45
|
@user = create(:user)
|
50
46
|
@return_url = '/url_in_the_request'
|
51
|
-
post :create, :session => {
|
52
|
-
|
53
|
-
:password => @user.password },
|
54
|
-
:return_to => @return_url
|
47
|
+
post :create, :session => { :email => @user.email, :password => @user.password },
|
48
|
+
:return_to => @return_url
|
55
49
|
end
|
56
50
|
|
57
|
-
it
|
51
|
+
it 'redirects to the return URL' do
|
58
52
|
should redirect_to(@return_url)
|
59
53
|
end
|
60
54
|
end
|
61
55
|
|
62
|
-
describe
|
56
|
+
describe 'on POST to #create with good credentials and a session return url and request return url' do
|
63
57
|
before do
|
64
58
|
@user = create(:user)
|
65
59
|
@return_url = '/url_in_the_session'
|
66
60
|
@request.session[:return_to] = @return_url
|
67
|
-
post :create, :session => {
|
68
|
-
|
69
|
-
:password => @user.password },
|
70
|
-
:return_to => '/url_in_the_request'
|
61
|
+
post :create, :session => { :email => @user.email, :password => @user.password },
|
62
|
+
:return_to => '/url_in_the_request'
|
71
63
|
end
|
72
64
|
|
73
|
-
it
|
65
|
+
it 'redirects to the return url' do
|
74
66
|
should redirect_to(@return_url)
|
75
67
|
end
|
76
68
|
end
|
77
69
|
|
78
|
-
describe
|
70
|
+
describe 'on DELETE to #destroy given a signed out user' do
|
79
71
|
before do
|
80
72
|
sign_out
|
81
73
|
delete :destroy
|
82
74
|
end
|
75
|
+
|
83
76
|
it { should redirect_to_url_after_destroy }
|
84
77
|
end
|
85
78
|
|
86
|
-
describe
|
79
|
+
describe 'on DELETE to #destroy with a cookie' do
|
87
80
|
before do
|
88
81
|
@user = create(:user)
|
89
|
-
@user.update_attribute
|
90
|
-
@request.cookies[
|
82
|
+
@user.update_attribute :remember_token, 'old-token'
|
83
|
+
@request.cookies['remember_token'] = 'old-token'
|
91
84
|
delete :destroy
|
92
85
|
end
|
93
86
|
|
94
87
|
it { should redirect_to_url_after_destroy }
|
95
88
|
|
96
|
-
it
|
97
|
-
@user.reload.remember_token.should_not ==
|
89
|
+
it 'should reset the remember token' do
|
90
|
+
@user.reload.remember_token.should_not == 'old-token'
|
98
91
|
end
|
99
92
|
|
100
|
-
it
|
93
|
+
it 'should unset the current user' do
|
101
94
|
@controller.current_user.should be_nil
|
102
95
|
end
|
103
96
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Clearance::UsersController do
|
4
|
-
describe
|
4
|
+
describe 'when signed out' do
|
5
5
|
before { sign_out }
|
6
6
|
|
7
|
-
describe
|
7
|
+
describe 'on GET to #new' do
|
8
8
|
before { get :new }
|
9
9
|
|
10
10
|
it { should respond_with(:success) }
|
@@ -12,18 +12,18 @@ describe Clearance::UsersController do
|
|
12
12
|
it { should_not set_the_flash }
|
13
13
|
end
|
14
14
|
|
15
|
-
describe
|
15
|
+
describe 'on GET to #new with email' do
|
16
16
|
before do
|
17
|
-
@email =
|
17
|
+
@email = 'a@example.com'
|
18
18
|
get :new, :user => { :email => @email }
|
19
19
|
end
|
20
20
|
|
21
|
-
it
|
21
|
+
it 'should set assigned user email' do
|
22
22
|
assigns(:user).email.should == @email
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
describe
|
26
|
+
describe 'on POST to #create with valid attributes' do
|
27
27
|
before do
|
28
28
|
user_attributes = FactoryGirl.attributes_for(:user)
|
29
29
|
@old_user_count = User.count
|
@@ -32,14 +32,14 @@ describe Clearance::UsersController do
|
|
32
32
|
|
33
33
|
it { should assign_to(:user) }
|
34
34
|
|
35
|
-
it
|
35
|
+
it 'should create a new user' do
|
36
36
|
User.count.should == @old_user_count + 1
|
37
37
|
end
|
38
38
|
|
39
39
|
it { should redirect_to_url_after_create }
|
40
40
|
end
|
41
41
|
|
42
|
-
describe
|
42
|
+
describe 'on POST to #create with valid attributes and a session return url' do
|
43
43
|
before do
|
44
44
|
user_attributes = FactoryGirl.attributes_for(:user)
|
45
45
|
@old_user_count = User.count
|
@@ -50,7 +50,7 @@ describe Clearance::UsersController do
|
|
50
50
|
|
51
51
|
it { should assign_to(:user) }
|
52
52
|
|
53
|
-
it
|
53
|
+
it 'should create a new user' do
|
54
54
|
User.count.should == @old_user_count + 1
|
55
55
|
end
|
56
56
|
|
@@ -58,22 +58,24 @@ describe Clearance::UsersController do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
describe
|
61
|
+
describe 'A signed-in user' do
|
62
62
|
before do
|
63
63
|
@user = create(:user)
|
64
64
|
sign_in_as @user
|
65
65
|
end
|
66
66
|
|
67
|
-
describe
|
67
|
+
describe 'GET to new' do
|
68
68
|
before { get :new }
|
69
|
-
|
69
|
+
|
70
|
+
it 'redirects to the home page' do
|
70
71
|
should redirect_to(root_url)
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
74
|
-
describe
|
75
|
+
describe 'POST to create' do
|
75
76
|
before { post :create, :user => {} }
|
76
|
-
|
77
|
+
|
78
|
+
it 'redirects to the home page' do
|
77
79
|
should redirect_to(root_url)
|
78
80
|
end
|
79
81
|
end
|
data/spec/factories.rb
CHANGED
@@ -7,21 +7,21 @@ describe ClearanceMailer do
|
|
7
7
|
@email = ClearanceMailer.change_password(@user)
|
8
8
|
end
|
9
9
|
|
10
|
-
it
|
10
|
+
it 'is from DO_NOT_REPLY' do
|
11
11
|
Clearance.configuration.mailer_sender.should =~ /#{@email.from[0]}/i
|
12
12
|
end
|
13
13
|
|
14
|
-
it
|
14
|
+
it 'is sent to user' do
|
15
15
|
@email.to.first.should =~ /#{@user.email}/i
|
16
16
|
end
|
17
17
|
|
18
|
-
it
|
18
|
+
it 'contains a link to edit the password' do
|
19
19
|
host = ActionMailer::Base.default_url_options[:host]
|
20
20
|
regexp = %r{http://#{host}/users/#{@user.id}/password/edit\?token=#{@user.confirmation_token}}
|
21
21
|
@email.body.to_s.should =~ regexp
|
22
22
|
end
|
23
23
|
|
24
|
-
it
|
24
|
+
it 'should set its subject' do
|
25
25
|
@email.subject.should =~ /Change your password/
|
26
26
|
end
|
27
27
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Clearance::PasswordStrategies::BCryptMigrationFromSHA1 do
|
4
|
+
subject do
|
5
|
+
Class.new do
|
6
|
+
attr_accessor :encrypted_password
|
7
|
+
attr_accessor :salt
|
8
|
+
include Clearance::PasswordStrategies::BCryptMigrationFromSHA1
|
9
|
+
end.new
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#password=' do
|
13
|
+
let(:salt) { 'salt' }
|
14
|
+
let(:password) { 'password' }
|
15
|
+
let(:encrypted_password) { stub('encrypted password') }
|
16
|
+
|
17
|
+
before do
|
18
|
+
subject.salt = salt
|
19
|
+
subject.encrypted_password = Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
20
|
+
BCrypt::Password.stubs :create => encrypted_password
|
21
|
+
subject.password = password
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'encrypts the password into a BCrypt-encrypted encrypted_password' do
|
25
|
+
subject.encrypted_password.should == encrypted_password
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'encrypts with BCrypt' do
|
29
|
+
BCrypt::Password.should have_received(:create).with(password)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#authenticated?' do
|
34
|
+
let(:password) { 'password' }
|
35
|
+
let(:salt) { 'salt' }
|
36
|
+
let(:sha1_hash) { Digest::SHA1.hexdigest("--#{salt}--#{password}--") }
|
37
|
+
|
38
|
+
context 'with a SHA1-encrypted password' do
|
39
|
+
before do
|
40
|
+
subject.salt = salt
|
41
|
+
subject.encrypted_password = sha1_hash
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'is authenticated' do
|
45
|
+
subject.should be_authenticated(password)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'changes the hash into a BCrypt-encrypted one' do
|
49
|
+
subject.authenticated? password
|
50
|
+
subject.encrypted_password.should_not == sha1_hash
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with a BCrypt-encrypted password' do
|
55
|
+
let(:bcrypt_hash) { ::BCrypt::Password.create(password) }
|
56
|
+
|
57
|
+
before do
|
58
|
+
subject.encrypted_password = bcrypt_hash
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'is authenticated' do
|
62
|
+
subject.should be_authenticated(password)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'does not change the hash' do
|
66
|
+
subject.authenticated? password
|
67
|
+
subject.encrypted_password.to_s.should == bcrypt_hash.to_s
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Clearance::PasswordStrategies::BCrypt do
|
4
|
+
subject do
|
5
|
+
Class.new do
|
6
|
+
attr_accessor :encrypted_password
|
7
|
+
include Clearance::PasswordStrategies::BCrypt
|
8
|
+
end.new
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#password=' do
|
12
|
+
let(:password) { 'password' }
|
13
|
+
let(:encrypted_password) { stub('encrypted password') }
|
14
|
+
|
15
|
+
before do
|
16
|
+
BCrypt::Password.stubs :create => encrypted_password
|
17
|
+
subject.password = password
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'encrypts the password into encrypted_password' do
|
21
|
+
subject.encrypted_password.should == encrypted_password
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'encrypts with BCrypt' do
|
25
|
+
BCrypt::Password.should have_received(:create).with(password)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#authenticated?' do
|
30
|
+
let(:password) { 'password' }
|
31
|
+
|
32
|
+
before do
|
33
|
+
subject.password = password
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'is authenticated with BCrypt' do
|
37
|
+
subject.should be_authenticated(password)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -3,41 +3,42 @@ require 'spec_helper'
|
|
3
3
|
describe Clearance::PasswordStrategies::Blowfish 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::Blowfish
|
8
8
|
|
9
|
-
def generate_random_code;
|
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
|
23
|
+
it 'does not initialize the salt' do
|
24
|
+
subject.salt.should == salt
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'encrypts the password using Blowfish and the existing salt' do
|
25
28
|
cipher = OpenSSL::Cipher::Cipher.new('bf-cbc').encrypt
|
26
29
|
cipher.key = Digest::SHA256.digest(salt)
|
27
30
|
expected = cipher.update("--#{salt}--#{password}--") << cipher.final
|
28
|
-
|
29
31
|
subject.encrypted_password.should == expected
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
context
|
35
|
+
context 'when the salt is not set' do
|
34
36
|
before do
|
35
37
|
subject.salt = nil
|
36
|
-
|
37
|
-
subject.send(:encrypt_password)
|
38
|
+
subject.password = 'whatever'
|
38
39
|
end
|
39
40
|
|
40
|
-
it
|
41
|
+
it 'should initialize the salt' do
|
41
42
|
subject.salt.should_not be_nil
|
42
43
|
end
|
43
44
|
end
|
@@ -13,21 +13,21 @@ describe Clearance::User do
|
|
13
13
|
end.new
|
14
14
|
end
|
15
15
|
|
16
|
-
describe
|
16
|
+
describe 'when Clearance.configuration.password_strategy is set' do
|
17
17
|
let(:mock_password_strategy) { Module.new }
|
18
18
|
|
19
19
|
before { Clearance.configuration.password_strategy = mock_password_strategy }
|
20
20
|
|
21
|
-
it
|
21
|
+
it 'includes the value it is set to' do
|
22
22
|
subject.should be_kind_of(mock_password_strategy)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
describe
|
26
|
+
describe 'when Clearance.configuration.password_strategy is not set' do
|
27
27
|
before { Clearance.configuration.password_strategy = nil }
|
28
28
|
|
29
|
-
it
|
30
|
-
subject.should be_kind_of(Clearance::PasswordStrategies::
|
29
|
+
it 'includes Clearance::PasswordStrategies::BCrypt' do
|
30
|
+
subject.should be_kind_of(Clearance::PasswordStrategies::BCrypt)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|