clearance 1.7.0 → 1.8.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.
- checksums.yaml +4 -4
- data/Gemfile +1 -3
- data/Gemfile.lock +4 -28
- data/NEWS.md +12 -0
- data/README.md +8 -1
- data/Rakefile +11 -8
- data/app/controllers/clearance/passwords_controller.rb +1 -0
- data/app/controllers/clearance/sessions_controller.rb +14 -2
- data/app/controllers/clearance/users_controller.rb +15 -4
- data/bin/appraisal +16 -0
- data/bin/rake +16 -0
- data/bin/rspec +16 -0
- data/clearance.gemspec +1 -1
- data/gemfiles/rails3.2.gemfile +1 -3
- data/gemfiles/rails4.0.gemfile +1 -3
- data/gemfiles/rails4.1.gemfile +1 -3
- data/gemfiles/rails4.2.gemfile +1 -3
- data/lib/clearance/configuration.rb +2 -0
- data/lib/clearance/session.rb +12 -6
- data/lib/clearance/version.rb +1 -1
- data/spec/acceptance/clearance_installation_spec.rb +75 -0
- data/spec/{support/app_templates → app_templates}/app/controllers/application_controller.rb +0 -0
- data/spec/{support/app_templates → app_templates}/app/models/user.rb +0 -0
- data/spec/{support/app_templates → app_templates}/config/routes.rb +0 -0
- data/spec/app_templates/testapp/Gemfile +7 -0
- data/spec/app_templates/testapp/app/controllers/home_controller.rb +5 -0
- data/spec/app_templates/testapp/config/initializers/action_mailer.rb +3 -0
- data/spec/app_templates/testapp/config/routes.rb +3 -0
- data/spec/clearance/session_spec.rb +13 -0
- data/spec/controllers/passwords_controller_spec.rb +100 -131
- data/spec/controllers/sessions_controller_spec.rb +66 -52
- data/spec/controllers/users_controller_spec.rb +47 -60
- data/spec/dummy/app/models/user.rb +3 -0
- data/spec/dummy/app/models/user_with_optional_password.rb +7 -0
- data/spec/dummy/application.rb +2 -0
- data/spec/factories.rb +4 -0
- data/spec/{models → password_strategies}/bcrypt_migration_from_sha1_spec.rb +1 -0
- data/spec/password_strategies/bcrypt_spec.rb +81 -0
- data/spec/password_strategies/blowfish_spec.rb +55 -0
- data/spec/password_strategies/password_strategies_spec.rb +28 -0
- data/spec/password_strategies/sha1_spec.rb +53 -0
- data/spec/support/clearance.rb +0 -16
- data/spec/support/fake_model_with_password_strategy.rb +0 -4
- data/spec/support/fake_model_without_password_strategy.rb +19 -0
- data/spec/support/generator_spec_helpers.rb +1 -1
- data/spec/support/request_with_remember_token.rb +1 -1
- data/spec/user_spec.rb +186 -0
- metadata +23 -67
- data/cucumber.yml +0 -1
- data/features/integration_with_rspec.feature +0 -23
- data/features/integration_with_test_unit.feature +0 -16
- data/features/step_definitions/configuration_steps.rb +0 -153
- data/features/step_definitions/gem_file_steps.rb +0 -15
- data/features/support/aruba.rb +0 -3
- data/features/support/env.rb +0 -27
- data/spec/models/bcrypt_spec.rb +0 -66
- data/spec/models/blowfish_spec.rb +0 -42
- data/spec/models/password_strategies_spec.rb +0 -41
- data/spec/models/sha1_spec.rb +0 -43
- data/spec/models/user_spec.rb +0 -196
data/lib/clearance/version.rb
CHANGED
@@ -0,0 +1,75 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Clearance Installation" do
|
4
|
+
around do |example|
|
5
|
+
Dir.chdir("tmp") do
|
6
|
+
FileUtils.rm_rf("testapp")
|
7
|
+
example.run
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can successfully run specs" do
|
12
|
+
app_name = "testapp"
|
13
|
+
generate_test_app(app_name)
|
14
|
+
|
15
|
+
Dir.chdir(app_name) do
|
16
|
+
configure_test_app
|
17
|
+
install_dependencies
|
18
|
+
configure_rspec
|
19
|
+
install_clearance
|
20
|
+
run_specs
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def generate_test_app(app_name)
|
25
|
+
successfully "bundle exec rails new #{app_name} \
|
26
|
+
--skip-gemfile \
|
27
|
+
--skip-bundle \
|
28
|
+
--skip-git \
|
29
|
+
--skip-javascript \
|
30
|
+
--skip-sprockets \
|
31
|
+
--skip-keeps"
|
32
|
+
|
33
|
+
FileUtils.rm_f("public/index.html")
|
34
|
+
FileUtils.rm_f("app/views/layouts/application.html.erb")
|
35
|
+
end
|
36
|
+
|
37
|
+
def testapp_templates
|
38
|
+
File.expand_path("../../app_templates/testapp/", __FILE__)
|
39
|
+
end
|
40
|
+
|
41
|
+
def configure_test_app
|
42
|
+
FileUtils.rm_f("public/index.html")
|
43
|
+
FileUtils.rm_f("app/views/layouts/application.html.erb")
|
44
|
+
FileUtils.cp_r(testapp_templates, "..")
|
45
|
+
end
|
46
|
+
|
47
|
+
def install_dependencies
|
48
|
+
successfully "bundle install --local"
|
49
|
+
end
|
50
|
+
|
51
|
+
def configure_rspec
|
52
|
+
successfully "bundle exec rails generate rspec:install"
|
53
|
+
end
|
54
|
+
|
55
|
+
def install_clearance
|
56
|
+
successfully "bundle exec rails generate clearance:install"
|
57
|
+
successfully "bundle exec rails generate clearance:specs"
|
58
|
+
successfully "bundle exec rake db:migrate db:test:prepare"
|
59
|
+
end
|
60
|
+
|
61
|
+
def run_specs
|
62
|
+
successfully "bundle exec rspec", false
|
63
|
+
end
|
64
|
+
|
65
|
+
def successfully(command, silent = true)
|
66
|
+
if silent
|
67
|
+
silencer = "1>/dev/null"
|
68
|
+
else
|
69
|
+
silencer = ""
|
70
|
+
end
|
71
|
+
|
72
|
+
return_value = system("#{command} #{silencer}")
|
73
|
+
expect(return_value).to eq true
|
74
|
+
end
|
75
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -30,6 +30,19 @@ describe Clearance::Session do
|
|
30
30
|
expect(session.current_user).to be_nil
|
31
31
|
end
|
32
32
|
|
33
|
+
context "with a custom cookie name" do
|
34
|
+
it "sets a custom cookie name in the header" do
|
35
|
+
Clearance.configuration.cookie_domain = "custom_token"
|
36
|
+
|
37
|
+
session.sign_in user
|
38
|
+
session.add_cookie_to_headers(headers)
|
39
|
+
|
40
|
+
expect(headers["Set-Cookie"]).to match(/custom_token/)
|
41
|
+
end
|
42
|
+
|
43
|
+
after { restore_default_config }
|
44
|
+
end
|
45
|
+
|
33
46
|
describe '#sign_in' do
|
34
47
|
it 'sets current_user' do
|
35
48
|
user = build(:user)
|
@@ -1,188 +1,157 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe Clearance::PasswordsController do
|
4
4
|
it { is_expected.to be_a Clearance::BaseController }
|
5
5
|
|
6
|
-
describe
|
7
|
-
|
8
|
-
|
9
|
-
end
|
6
|
+
describe "#new" do
|
7
|
+
it "renders the password reset form" do
|
8
|
+
user = create(:user)
|
10
9
|
|
11
|
-
|
12
|
-
before { get :new, user_id: @user.to_param }
|
10
|
+
get :new, user_id: user
|
13
11
|
|
14
|
-
|
15
|
-
|
12
|
+
expect(response).to be_success
|
13
|
+
expect(response).to render_template(:new)
|
16
14
|
end
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
post :create, password: { email: @user.email }
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'should generate a token for the change your password email' do
|
26
|
-
expect(@user.reload.confirmation_token).not_to be_nil
|
27
|
-
end
|
17
|
+
describe "#create" do
|
18
|
+
context "email corresponds to an existing user" do
|
19
|
+
it "generates a password change token" do
|
20
|
+
user = create(:user)
|
28
21
|
|
29
|
-
|
30
|
-
email = ActionMailer::Base.deliveries.last
|
31
|
-
expect(email.subject).to match(/change your password/i)
|
32
|
-
end
|
22
|
+
post :create, password: { email: user.email.upcase }
|
33
23
|
|
34
|
-
|
24
|
+
expect(user.reload.confirmation_token).not_to be_nil
|
35
25
|
end
|
36
26
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
post :create, password: { email: @user.email.upcase }
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'should generate a token for the change your password email' do
|
44
|
-
expect(@user.reload.confirmation_token).not_to be_nil
|
45
|
-
end
|
27
|
+
it "sends the password reset email" do
|
28
|
+
ActionMailer::Base.deliveries.clear
|
29
|
+
user = create(:user)
|
46
30
|
|
47
|
-
|
48
|
-
email = ActionMailer::Base.deliveries.last
|
49
|
-
expect(email.subject).to match(/change your password/i)
|
50
|
-
end
|
31
|
+
post :create, password: { email: user.email }
|
51
32
|
|
52
|
-
|
33
|
+
email = ActionMailer::Base.deliveries.last
|
34
|
+
expect(email.subject).to match(/change your password/i)
|
53
35
|
end
|
36
|
+
end
|
54
37
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
expect(user).not_to be_present
|
38
|
+
context "email does not belong to an existing user" do
|
39
|
+
it "does not deliver an email" do
|
40
|
+
ActionMailer::Base.deliveries.clear
|
41
|
+
email = "this_user_does_not_exist@non_existent_domain.com"
|
60
42
|
|
61
|
-
|
62
|
-
expect(@user.reload.confirmation_token).to eq @user.confirmation_token
|
43
|
+
post :create, password: { email: email }
|
63
44
|
|
64
|
-
|
65
|
-
|
45
|
+
expect(ActionMailer::Base.deliveries).to be_empty
|
46
|
+
end
|
66
47
|
|
67
|
-
|
68
|
-
|
69
|
-
end
|
48
|
+
it "still responds with success so as not to leak registered users" do
|
49
|
+
email = "this_user_does_not_exist@non_existent_domain.com"
|
70
50
|
|
71
|
-
|
72
|
-
expect(ActionMailer::Base.deliveries).to be_empty
|
73
|
-
end
|
51
|
+
post :create, password: { email: email }
|
74
52
|
|
75
|
-
|
53
|
+
expect(response).to be_success
|
54
|
+
expect(response).to render_template "passwords/create"
|
76
55
|
end
|
77
56
|
end
|
78
57
|
end
|
79
58
|
|
80
|
-
describe
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
59
|
+
describe "#edit" do
|
60
|
+
context "valid id and token are supplied" do
|
61
|
+
it "renders the password form for the user" do
|
62
|
+
user = create(:user, :with_forgotten_password)
|
85
63
|
|
86
|
-
|
87
|
-
before do
|
88
|
-
get :edit,
|
89
|
-
user_id: @user.to_param,
|
90
|
-
token: @user.confirmation_token
|
91
|
-
end
|
64
|
+
get :edit, user_id: user, token: user.confirmation_token
|
92
65
|
|
93
|
-
|
94
|
-
expect(
|
66
|
+
expect(response).to be_success
|
67
|
+
expect(response).to render_template(:edit)
|
68
|
+
expect(assigns(:user)).to eq user
|
95
69
|
end
|
96
|
-
|
97
|
-
it { is_expected.to respond_with(:success) }
|
98
|
-
it { is_expected.to render_template(:edit) }
|
99
70
|
end
|
100
71
|
|
101
|
-
|
102
|
-
|
103
|
-
get :edit, user_id:
|
104
|
-
end
|
72
|
+
context "blank token is supplied" do
|
73
|
+
it "renders the new password reset form with a flash notice" do
|
74
|
+
get :edit, user_id: 1, token: ""
|
105
75
|
|
106
|
-
|
107
|
-
|
76
|
+
expect(response).to render_template(:new)
|
77
|
+
expect(flash.now[:notice]).to match(/double check the URL/i)
|
78
|
+
end
|
108
79
|
end
|
109
80
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
end
|
81
|
+
context "invalid token is supplied" do
|
82
|
+
it "renders the new password reset form with a flash notice" do
|
83
|
+
user = create(:user, :with_forgotten_password)
|
114
84
|
|
115
|
-
|
116
|
-
|
85
|
+
get :edit, user_id: 1, token: user.confirmation_token + "a"
|
86
|
+
|
87
|
+
expect(response).to render_template(:new)
|
88
|
+
expect(flash.now[:notice]).to match(/double check the URL/i)
|
89
|
+
end
|
117
90
|
end
|
91
|
+
end
|
118
92
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
93
|
+
describe "#update" do
|
94
|
+
context "valid id, token, and new password provided" do
|
95
|
+
it "updates the user's password" do
|
96
|
+
user = create(:user, :with_forgotten_password)
|
97
|
+
old_encrypted_password = user.encrypted_password
|
123
98
|
|
124
|
-
put :update,
|
125
|
-
password_reset: { password: @new_password }
|
126
|
-
@user.reload
|
127
|
-
end
|
99
|
+
put :update, update_parameters(user, new_password: "my_new_password")
|
128
100
|
|
129
|
-
|
130
|
-
expect(@user.encrypted_password.to_s).not_to eq @old_encrypted_password
|
101
|
+
expect(user.reload.encrypted_password).not_to eq old_encrypted_password
|
131
102
|
end
|
132
103
|
|
133
|
-
it
|
134
|
-
|
135
|
-
end
|
104
|
+
it "sets the remember token and clears the confirmation token" do
|
105
|
+
user = create(:user, :with_forgotten_password)
|
136
106
|
|
137
|
-
|
138
|
-
|
107
|
+
put :update, update_parameters(user, new_password: "my_new_password")
|
108
|
+
|
109
|
+
user.reload
|
110
|
+
expect(user.remember_token).not_to be_nil
|
111
|
+
expect(user.confirmation_token).to be_nil
|
139
112
|
end
|
140
113
|
|
141
|
-
it
|
142
|
-
|
114
|
+
it "signs the user in and redirects" do
|
115
|
+
user = create(:user, :with_forgotten_password)
|
143
116
|
|
144
|
-
|
145
|
-
before do
|
146
|
-
put :update, user_id: @user.to_param, token: @user.confirmation_token,
|
147
|
-
password_reset: { password: '' }
|
148
|
-
@user.reload
|
149
|
-
end
|
117
|
+
put :update, update_parameters(user, new_password: "my_new_password")
|
150
118
|
|
151
|
-
|
152
|
-
expect(
|
119
|
+
expect(response).to redirect_to(Clearance.configuration.redirect_url)
|
120
|
+
expect(cookies[:remember_token]).to be_present
|
153
121
|
end
|
122
|
+
end
|
154
123
|
|
155
|
-
|
156
|
-
|
157
|
-
|
124
|
+
context "no password provided" do
|
125
|
+
it "does not update the password" do
|
126
|
+
user = create(:user, :with_forgotten_password)
|
127
|
+
old_encrypted_password = user.encrypted_password
|
158
128
|
|
159
|
-
|
160
|
-
|
129
|
+
put :update, update_parameters(user, new_password: "")
|
130
|
+
|
131
|
+
user.reload
|
132
|
+
expect(user.encrypted_password).to eq old_encrypted_password
|
133
|
+
expect(user.confirmation_token).to be_present
|
161
134
|
end
|
162
135
|
|
163
|
-
it
|
164
|
-
|
165
|
-
it { is_expected.to render_template(:edit) }
|
166
|
-
end
|
136
|
+
it "re-renders the password edit form" do
|
137
|
+
user = create(:user, :with_forgotten_password)
|
167
138
|
|
168
|
-
|
169
|
-
before do
|
170
|
-
put :update, user_id: @user.to_param, token: @user.confirmation_token,
|
171
|
-
password_reset: { password: 'good password' }
|
172
|
-
put :update, user_id: @user.to_param, token: [nil],
|
173
|
-
password_reset: { password: 'new password' }
|
174
|
-
end
|
139
|
+
put :update, update_parameters(user, new_password: "")
|
175
140
|
|
176
|
-
|
177
|
-
|
141
|
+
expect(flash.now[:notice]).to match(/password can't be blank/i)
|
142
|
+
expect(response).to render_template(:edit)
|
143
|
+
expect(cookies[:remember_token]).to be_nil
|
144
|
+
end
|
178
145
|
end
|
179
146
|
end
|
180
147
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
148
|
+
def update_parameters(user, options = {})
|
149
|
+
new_password = options.fetch(:new_password)
|
150
|
+
|
151
|
+
{
|
152
|
+
user_id: user,
|
153
|
+
token: user.confirmation_token,
|
154
|
+
password_reset: { password: new_password }
|
155
|
+
}
|
187
156
|
end
|
188
157
|
end
|
@@ -1,19 +1,31 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe Clearance::SessionsController do
|
4
4
|
it { should be_a Clearance::BaseController }
|
5
5
|
|
6
|
-
describe
|
7
|
-
|
6
|
+
describe "on GET to #new" do
|
7
|
+
context "when a user is not signed in" do
|
8
|
+
before { get :new }
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
it { should respond_with(:success) }
|
11
|
+
it { should render_template(:new) }
|
12
|
+
it { should_not set_the_flash }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when a user is signed in" do
|
16
|
+
before do
|
17
|
+
sign_in
|
18
|
+
get :new
|
19
|
+
end
|
20
|
+
|
21
|
+
it { should redirect_to(Clearance.configuration.redirect_url) }
|
22
|
+
it { should_not set_the_flash }
|
23
|
+
end
|
12
24
|
end
|
13
25
|
|
14
|
-
|
15
|
-
|
16
|
-
it
|
26
|
+
describe "on POST to #create" do
|
27
|
+
context "when password is optional" do
|
28
|
+
it "renders the page with error" do
|
17
29
|
user = create(:user_with_optional_password)
|
18
30
|
|
19
31
|
post :create, session: { email: user.email, password: user.password }
|
@@ -22,64 +34,66 @@ describe Clearance::SessionsController do
|
|
22
34
|
expect(flash[:notice]).to match(/^Bad email or password/)
|
23
35
|
end
|
24
36
|
end
|
25
|
-
end
|
26
37
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
38
|
+
context "with good credentials" do
|
39
|
+
before do
|
40
|
+
@user = create(:user)
|
41
|
+
@user.update_attribute :remember_token, "old-token"
|
42
|
+
post :create, session: { email: @user.email, password: @user.password }
|
43
|
+
end
|
33
44
|
|
34
|
-
|
45
|
+
it { should redirect_to_url_after_create }
|
35
46
|
|
36
|
-
|
37
|
-
|
38
|
-
|
47
|
+
it "sets the user in the clearance session" do
|
48
|
+
expect(controller.current_user).to eq @user
|
49
|
+
end
|
39
50
|
|
40
|
-
|
41
|
-
|
51
|
+
it "should not change the remember token" do
|
52
|
+
expect(@user.reload.remember_token).to eq "old-token"
|
53
|
+
end
|
42
54
|
end
|
43
|
-
end
|
44
55
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
56
|
+
context "with good credentials and a session return url" do
|
57
|
+
before do
|
58
|
+
@user = create(:user)
|
59
|
+
@return_url = "/url_in_the_session?foo=bar"
|
60
|
+
@request.session[:return_to] = @return_url
|
61
|
+
post :create, session: { email: @user.email, password: @user.password }
|
62
|
+
end
|
52
63
|
|
53
|
-
|
54
|
-
|
64
|
+
it "redirects to the return URL" do
|
65
|
+
should redirect_to(@return_url)
|
66
|
+
end
|
55
67
|
end
|
56
68
|
end
|
57
69
|
|
58
|
-
describe
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
it { should redirect_to_url_after_destroy }
|
65
|
-
end
|
70
|
+
describe "on DELETE to #destroy" do
|
71
|
+
context "given a signed out user" do
|
72
|
+
before do
|
73
|
+
sign_out
|
74
|
+
delete :destroy
|
75
|
+
end
|
66
76
|
|
67
|
-
|
68
|
-
before do
|
69
|
-
@user = create(:user)
|
70
|
-
@user.update_attribute :remember_token, 'old-token'
|
71
|
-
@request.cookies['remember_token'] = 'old-token'
|
72
|
-
delete :destroy
|
77
|
+
it { should redirect_to_url_after_destroy }
|
73
78
|
end
|
74
79
|
|
75
|
-
|
80
|
+
context "with a cookie" do
|
81
|
+
before do
|
82
|
+
@user = create(:user)
|
83
|
+
@user.update_attribute :remember_token, "old-token"
|
84
|
+
@request.cookies["remember_token"] = "old-token"
|
85
|
+
delete :destroy
|
86
|
+
end
|
76
87
|
|
77
|
-
|
78
|
-
expect(@user.reload.remember_token).not_to eq 'old-token'
|
79
|
-
end
|
88
|
+
it { should redirect_to_url_after_destroy }
|
80
89
|
|
81
|
-
|
82
|
-
|
90
|
+
it "should reset the remember token" do
|
91
|
+
expect(@user.reload.remember_token).not_to eq "old-token"
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should unset the current user" do
|
95
|
+
expect(@controller.current_user).to be_nil
|
96
|
+
end
|
83
97
|
end
|
84
98
|
end
|
85
99
|
end
|