clearance 1.10.1 → 1.17.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 +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +20 -8
- data/.yardopts +3 -0
- data/Appraisals +13 -16
- data/Gemfile +7 -5
- data/Gemfile.lock +124 -130
- data/NEWS.md +171 -2
- data/README.md +99 -42
- data/app/controllers/clearance/passwords_controller.rb +35 -21
- data/app/controllers/clearance/sessions_controller.rb +17 -3
- data/app/controllers/clearance/users_controller.rb +10 -4
- data/app/mailers/clearance_mailer.rb +2 -3
- data/app/views/clearance_mailer/change_password.text.erb +1 -1
- data/app/views/layouts/application.html.erb +0 -1
- data/bin/setup +6 -2
- data/clearance.gemspec +5 -2
- data/config/locales/clearance.en.yml +9 -0
- data/gemfiles/rails_4.2.gemfile +20 -0
- data/gemfiles/rails_5.0.gemfile +21 -0
- data/gemfiles/rails_5.1.gemfile +21 -0
- data/gemfiles/rails_5.2.gemfile +21 -0
- data/lib/clearance/authentication.rb +63 -3
- data/lib/clearance/authorization.rb +48 -5
- data/lib/clearance/back_door.rb +55 -6
- data/lib/clearance/configuration.rb +50 -10
- data/lib/clearance/constraints/signed_in.rb +21 -0
- data/lib/clearance/constraints/signed_out.rb +12 -0
- data/lib/clearance/constraints.rb +12 -0
- data/lib/clearance/controller.rb +13 -0
- data/lib/clearance/default_sign_in_guard.rb +17 -0
- data/lib/clearance/engine.rb +18 -5
- data/lib/clearance/password_strategies/bcrypt.rb +16 -21
- data/lib/clearance/password_strategies/bcrypt_migration_from_sha1.rb +10 -0
- data/lib/clearance/password_strategies/blowfish.rb +10 -1
- data/lib/clearance/password_strategies/sha1.rb +9 -0
- data/lib/clearance/password_strategies.rb +13 -0
- data/lib/clearance/rack_session.rb +13 -0
- data/lib/clearance/rspec.rb +15 -4
- data/lib/clearance/session.rb +62 -13
- data/lib/clearance/session_status.rb +7 -0
- data/lib/clearance/sign_in_guard.rb +65 -0
- data/lib/clearance/test_unit.rb +3 -3
- data/lib/clearance/testing/controller_helpers.rb +57 -0
- data/lib/clearance/testing/deny_access_matcher.rb +36 -2
- data/lib/clearance/testing/helpers.rb +9 -25
- data/lib/clearance/testing/view_helpers.rb +32 -0
- data/lib/clearance/token.rb +7 -0
- data/lib/clearance/user.rb +183 -4
- data/lib/clearance/version.rb +1 -1
- data/lib/generators/clearance/install/install_generator.rb +28 -9
- data/lib/generators/clearance/install/templates/README +1 -1
- data/lib/generators/clearance/install/templates/clearance.rb +1 -0
- data/lib/generators/clearance/install/templates/db/migrate/{add_clearance_to_users.rb → add_clearance_to_users.rb.erb} +3 -3
- data/lib/generators/clearance/install/templates/db/migrate/{create_users.rb → create_users.rb.erb} +2 -2
- data/lib/generators/clearance/install/templates/user.rb.erb +3 -0
- data/lib/generators/clearance/routes/routes_generator.rb +23 -0
- data/lib/generators/clearance/routes/templates/routes.rb +7 -7
- data/lib/generators/clearance/specs/templates/factories/clearance.rb +2 -2
- data/lib/generators/clearance/specs/templates/features/clearance/user_signs_out_spec.rb.tt +1 -1
- data/lib/generators/clearance/specs/templates/features/clearance/visitor_resets_password_spec.rb.tt +12 -3
- data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_in_spec.rb.tt +3 -3
- data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_up_spec.rb.tt +1 -1
- data/lib/generators/clearance/specs/templates/features/clearance/visitor_updates_password_spec.rb.tt +2 -2
- data/lib/generators/clearance/specs/templates/support/features/clearance_helpers.rb +2 -2
- data/spec/acceptance/clearance_installation_spec.rb +15 -7
- data/spec/app_templates/app/models/rails5/user.rb +5 -0
- data/spec/app_templates/config/initializers/clearance.rb +2 -0
- data/spec/app_templates/testapp/Gemfile +1 -1
- data/spec/app_templates/testapp/app/controllers/home_controller.rb +5 -1
- data/spec/clearance/back_door_spec.rb +70 -6
- data/spec/clearance/session_spec.rb +4 -16
- data/spec/clearance/testing/controller_helpers_spec.rb +38 -0
- data/spec/clearance/testing/view_helpers_spec.rb +37 -0
- data/spec/configuration_spec.rb +79 -86
- data/spec/controllers/apis_controller_spec.rb +6 -2
- data/spec/controllers/forgeries_controller_spec.rb +12 -3
- data/spec/controllers/passwords_controller_spec.rb +74 -38
- data/spec/controllers/permissions_controller_spec.rb +13 -3
- data/spec/controllers/sessions_controller_spec.rb +40 -11
- data/spec/controllers/users_controller_spec.rb +16 -8
- data/spec/dummy/app/controllers/application_controller.rb +5 -1
- data/spec/dummy/application.rb +9 -11
- data/spec/factories.rb +5 -5
- data/spec/generators/clearance/install/install_generator_spec.rb +29 -3
- data/spec/generators/clearance/routes/routes_generator_spec.rb +5 -1
- data/spec/helpers/helper_helpers_spec.rb +10 -0
- data/spec/{user_spec.rb → models/user_spec.rb} +10 -1
- data/spec/password_strategies/blowfish_spec.rb +1 -1
- data/spec/requests/cookie_options_spec.rb +52 -0
- data/spec/requests/csrf_rotation_spec.rb +35 -0
- data/spec/requests/password_maintenance_spec.rb +18 -0
- data/spec/requests/token_expiration_spec.rb +54 -0
- data/spec/spec_helper.rb +22 -4
- data/spec/support/environment.rb +12 -0
- data/spec/support/generator_spec_helpers.rb +13 -1
- data/spec/support/http_method_shim.rb +25 -0
- data/spec/support/request_with_remember_token.rb +5 -0
- data/spec/views/view_helpers_spec.rb +10 -0
- metadata +69 -15
- data/gemfiles/rails3.2.gemfile +0 -18
- data/gemfiles/rails4.0.gemfile +0 -19
- data/gemfiles/rails4.1.gemfile +0 -18
- data/gemfiles/rails4.2.gemfile +0 -18
- data/lib/generators/clearance/install/templates/user.rb +0 -3
- data/spec/clearance/testing/helpers_spec.rb +0 -38
@@ -5,11 +5,9 @@ describe Clearance::PasswordsController do
|
|
5
5
|
|
6
6
|
describe "#new" do
|
7
7
|
it "renders the password reset form" do
|
8
|
-
|
8
|
+
get :new
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
expect(response).to be_success
|
10
|
+
expect(response).to be_successful
|
13
11
|
expect(response).to render_template(:new)
|
14
12
|
end
|
15
13
|
end
|
@@ -19,7 +17,9 @@ describe Clearance::PasswordsController do
|
|
19
17
|
it "generates a password change token" do
|
20
18
|
user = create(:user)
|
21
19
|
|
22
|
-
post :create,
|
20
|
+
post :create, params: {
|
21
|
+
password: { email: user.email.upcase },
|
22
|
+
}
|
23
23
|
|
24
24
|
expect(user.reload.confirmation_token).not_to be_nil
|
25
25
|
end
|
@@ -28,7 +28,9 @@ describe Clearance::PasswordsController do
|
|
28
28
|
ActionMailer::Base.deliveries.clear
|
29
29
|
user = create(:user)
|
30
30
|
|
31
|
-
post :create,
|
31
|
+
post :create, params: {
|
32
|
+
password: { email: user.email },
|
33
|
+
}
|
32
34
|
|
33
35
|
email = ActionMailer::Base.deliveries.last
|
34
36
|
expect(email.subject).to match(/change your password/i)
|
@@ -40,7 +42,9 @@ describe Clearance::PasswordsController do
|
|
40
42
|
ActionMailer::Base.deliveries.clear
|
41
43
|
email = "this_user_does_not_exist@non_existent_domain.com"
|
42
44
|
|
43
|
-
post :create,
|
45
|
+
post :create, params: {
|
46
|
+
password: { email: email },
|
47
|
+
}
|
44
48
|
|
45
49
|
expect(ActionMailer::Base.deliveries).to be_empty
|
46
50
|
end
|
@@ -48,22 +52,42 @@ describe Clearance::PasswordsController do
|
|
48
52
|
it "still responds with success so as not to leak registered users" do
|
49
53
|
email = "this_user_does_not_exist@non_existent_domain.com"
|
50
54
|
|
51
|
-
post :create,
|
55
|
+
post :create, params: {
|
56
|
+
password: { email: email },
|
57
|
+
}
|
52
58
|
|
53
|
-
expect(response).to
|
59
|
+
expect(response).to be_successful
|
54
60
|
expect(response).to render_template "passwords/create"
|
55
61
|
end
|
56
62
|
end
|
57
63
|
end
|
58
64
|
|
59
65
|
describe "#edit" do
|
60
|
-
context "valid id and token are supplied" do
|
61
|
-
it "
|
66
|
+
context "valid id and token are supplied in url" do
|
67
|
+
it "redirects to the edit page with token now removed from url" do
|
68
|
+
user = create(:user, :with_forgotten_password)
|
69
|
+
|
70
|
+
get :edit, params: {
|
71
|
+
user_id: user,
|
72
|
+
token: user.confirmation_token,
|
73
|
+
}
|
74
|
+
|
75
|
+
expect(response).to be_redirect
|
76
|
+
expect(response).to redirect_to edit_user_password_url(user)
|
77
|
+
expect(session[:password_reset_token]).to eq user.confirmation_token
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "valid id in url and valid token in session" do
|
82
|
+
it "renders the password reset form" do
|
62
83
|
user = create(:user, :with_forgotten_password)
|
63
84
|
|
64
|
-
|
85
|
+
request.session[:password_reset_token] = user.confirmation_token
|
86
|
+
get :edit, params: {
|
87
|
+
user_id: user,
|
88
|
+
}
|
65
89
|
|
66
|
-
expect(response).to
|
90
|
+
expect(response).to be_successful
|
67
91
|
expect(response).to render_template(:edit)
|
68
92
|
expect(assigns(:user)).to eq user
|
69
93
|
end
|
@@ -71,7 +95,10 @@ describe Clearance::PasswordsController do
|
|
71
95
|
|
72
96
|
context "blank token is supplied" do
|
73
97
|
it "renders the new password reset form with a flash notice" do
|
74
|
-
get :edit,
|
98
|
+
get :edit, params: {
|
99
|
+
user_id: 1,
|
100
|
+
token: "",
|
101
|
+
}
|
75
102
|
|
76
103
|
expect(response).to render_template(:new)
|
77
104
|
expect(flash.now[:notice]).to match(/double check the URL/i)
|
@@ -82,12 +109,31 @@ describe Clearance::PasswordsController do
|
|
82
109
|
it "renders the new password reset form with a flash notice" do
|
83
110
|
user = create(:user, :with_forgotten_password)
|
84
111
|
|
85
|
-
get :edit,
|
112
|
+
get :edit, params: {
|
113
|
+
user_id: 1,
|
114
|
+
token: user.confirmation_token + "a",
|
115
|
+
}
|
86
116
|
|
87
117
|
expect(response).to render_template(:new)
|
88
118
|
expect(flash.now[:notice]).to match(/double check the URL/i)
|
89
119
|
end
|
90
120
|
end
|
121
|
+
|
122
|
+
context "old token in session and recent token in params" do
|
123
|
+
it "updates password reset session and redirect to edit page" do
|
124
|
+
user = create(:user, :with_forgotten_password)
|
125
|
+
request.session[:password_reset_token] = user.confirmation_token
|
126
|
+
|
127
|
+
user.forgot_password!
|
128
|
+
get :edit, params: {
|
129
|
+
user_id: user.id,
|
130
|
+
token: user.reload.confirmation_token,
|
131
|
+
}
|
132
|
+
|
133
|
+
expect(response).to redirect_to(edit_user_password_url(user))
|
134
|
+
expect(session[:password_reset_token]).to eq(user.confirmation_token)
|
135
|
+
end
|
136
|
+
end
|
91
137
|
end
|
92
138
|
|
93
139
|
describe "#update" do
|
@@ -96,37 +142,24 @@ describe Clearance::PasswordsController do
|
|
96
142
|
user = create(:user, :with_forgotten_password)
|
97
143
|
old_encrypted_password = user.encrypted_password
|
98
144
|
|
99
|
-
put :update, update_parameters(
|
145
|
+
put :update, params: update_parameters(
|
146
|
+
user,
|
147
|
+
new_password: "my_new_password",
|
148
|
+
)
|
100
149
|
|
101
150
|
expect(user.reload.encrypted_password).not_to eq old_encrypted_password
|
102
151
|
end
|
103
|
-
|
104
|
-
it "sets the remember token and clears the confirmation token" do
|
105
|
-
user = create(:user, :with_forgotten_password)
|
106
|
-
|
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
|
112
|
-
end
|
113
|
-
|
114
|
-
it "signs the user in and redirects" do
|
115
|
-
user = create(:user, :with_forgotten_password)
|
116
|
-
|
117
|
-
put :update, update_parameters(user, new_password: "my_new_password")
|
118
|
-
|
119
|
-
expect(response).to redirect_to(Clearance.configuration.redirect_url)
|
120
|
-
expect(cookies[:remember_token]).to be_present
|
121
|
-
end
|
122
152
|
end
|
123
153
|
|
124
|
-
context "
|
154
|
+
context "password update fails" do
|
125
155
|
it "does not update the password" do
|
126
156
|
user = create(:user, :with_forgotten_password)
|
127
157
|
old_encrypted_password = user.encrypted_password
|
128
158
|
|
129
|
-
put :update, update_parameters(
|
159
|
+
put :update, params: update_parameters(
|
160
|
+
user,
|
161
|
+
new_password: "",
|
162
|
+
)
|
130
163
|
|
131
164
|
user.reload
|
132
165
|
expect(user.encrypted_password).to eq old_encrypted_password
|
@@ -136,7 +169,10 @@ describe Clearance::PasswordsController do
|
|
136
169
|
it "re-renders the password edit form" do
|
137
170
|
user = create(:user, :with_forgotten_password)
|
138
171
|
|
139
|
-
put :update, update_parameters(
|
172
|
+
put :update, params: update_parameters(
|
173
|
+
user,
|
174
|
+
new_password: "",
|
175
|
+
)
|
140
176
|
|
141
177
|
expect(flash.now[:notice]).to match(/password can't be blank/i)
|
142
178
|
expect(response).to render_template(:edit)
|
@@ -3,14 +3,18 @@ require 'spec_helper'
|
|
3
3
|
class PermissionsController < ActionController::Base
|
4
4
|
include Clearance::Controller
|
5
5
|
|
6
|
-
|
6
|
+
if respond_to?(:before_action)
|
7
|
+
before_action :require_login, only: :show
|
8
|
+
else
|
9
|
+
before_filter :require_login, only: :show
|
10
|
+
end
|
7
11
|
|
8
12
|
def new
|
9
|
-
|
13
|
+
head :ok
|
10
14
|
end
|
11
15
|
|
12
16
|
def show
|
13
|
-
|
17
|
+
head :ok
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
@@ -54,6 +58,12 @@ describe PermissionsController do
|
|
54
58
|
|
55
59
|
expect(subject).to deny_access(redirect: sign_in_url)
|
56
60
|
end
|
61
|
+
|
62
|
+
it "denies access to show and display a flash message" do
|
63
|
+
get :show
|
64
|
+
|
65
|
+
expect(flash[:notice]).to match(/^Please sign in to continue/)
|
66
|
+
end
|
57
67
|
end
|
58
68
|
|
59
69
|
context 'when remember_token is blank' do
|
@@ -28,7 +28,9 @@ describe Clearance::SessionsController do
|
|
28
28
|
it "renders the page with error" do
|
29
29
|
user = create(:user_with_optional_password)
|
30
30
|
|
31
|
-
post :create,
|
31
|
+
post :create, params: {
|
32
|
+
session: { email: user.email, password: user.password },
|
33
|
+
}
|
32
34
|
|
33
35
|
expect(response).to render_template(:new)
|
34
36
|
expect(flash[:notice]).to match(/^Bad email or password/)
|
@@ -39,13 +41,15 @@ describe Clearance::SessionsController do
|
|
39
41
|
before do
|
40
42
|
@user = create(:user)
|
41
43
|
@user.update_attribute :remember_token, "old-token"
|
42
|
-
post :create,
|
44
|
+
post :create, params: {
|
45
|
+
session: { email: @user.email, password: @user.password },
|
46
|
+
}
|
43
47
|
end
|
44
48
|
|
45
49
|
it { should redirect_to_url_after_create }
|
46
50
|
|
47
51
|
it "sets the user in the clearance session" do
|
48
|
-
expect(
|
52
|
+
expect(request.env[:clearance].current_user).to eq @user
|
49
53
|
end
|
50
54
|
|
51
55
|
it "should not change the remember token" do
|
@@ -54,15 +58,40 @@ describe Clearance::SessionsController do
|
|
54
58
|
end
|
55
59
|
|
56
60
|
context "with good credentials and a session return url" do
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
61
|
+
it "redirects to the return URL maintaining query and fragment" do
|
62
|
+
user = create(:user)
|
63
|
+
return_url = "/url_in_the_session?foo=bar#baz"
|
64
|
+
request.session[:return_to] = return_url
|
65
|
+
|
66
|
+
post :create, params: {
|
67
|
+
session: { email: user.email, password: user.password },
|
68
|
+
}
|
69
|
+
|
70
|
+
should redirect_to(return_url)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "redirects to the return URL maintaining query without fragment" do
|
74
|
+
user = create(:user)
|
75
|
+
return_url = "/url_in_the_session?foo=bar"
|
76
|
+
request.session[:return_to] = return_url
|
77
|
+
|
78
|
+
post :create, params: {
|
79
|
+
session: { email: user.email, password: user.password },
|
80
|
+
}
|
81
|
+
|
82
|
+
should redirect_to(return_url)
|
62
83
|
end
|
63
84
|
|
64
|
-
it "redirects to the return URL" do
|
65
|
-
|
85
|
+
it "redirects to the return URL without query or fragment" do
|
86
|
+
user = create(:user)
|
87
|
+
return_url = "/url_in_the_session"
|
88
|
+
request.session[:return_to] = return_url
|
89
|
+
|
90
|
+
post :create, params: {
|
91
|
+
session: { email: user.email, password: user.password },
|
92
|
+
}
|
93
|
+
|
94
|
+
should redirect_to(return_url)
|
66
95
|
end
|
67
96
|
end
|
68
97
|
end
|
@@ -92,7 +121,7 @@ describe Clearance::SessionsController do
|
|
92
121
|
end
|
93
122
|
|
94
123
|
it "should unset the current user" do
|
95
|
-
expect(
|
124
|
+
expect(request.env[:clearance].current_user).to be_nil
|
96
125
|
end
|
97
126
|
end
|
98
127
|
end
|
@@ -8,15 +8,17 @@ describe Clearance::UsersController do
|
|
8
8
|
it "renders a form for a new user" do
|
9
9
|
get :new
|
10
10
|
|
11
|
-
expect(response).to
|
11
|
+
expect(response).to be_successful
|
12
12
|
expect(response).to render_template(:new)
|
13
13
|
end
|
14
14
|
|
15
15
|
it "defaults email field to the value provided in the query string" do
|
16
|
-
get :new,
|
16
|
+
get :new, params: {
|
17
|
+
user: { email: "a@example.com" },
|
18
|
+
}
|
17
19
|
|
18
20
|
expect(assigns(:user).email).to eq "a@example.com"
|
19
|
-
expect(response).to
|
21
|
+
expect(response).to be_successful
|
20
22
|
expect(response).to render_template(:new)
|
21
23
|
end
|
22
24
|
end
|
@@ -36,10 +38,12 @@ describe Clearance::UsersController do
|
|
36
38
|
context "when signed out" do
|
37
39
|
context "with valid attributes" do
|
38
40
|
it "assigns and creates a user then redirects to the redirect_url" do
|
39
|
-
user_attributes =
|
41
|
+
user_attributes = FactoryBot.attributes_for(:user)
|
40
42
|
old_user_count = User.count
|
41
43
|
|
42
|
-
post :create,
|
44
|
+
post :create, params: {
|
45
|
+
user: user_attributes,
|
46
|
+
}
|
43
47
|
|
44
48
|
expect(assigns(:user)).to be_present
|
45
49
|
expect(User.count).to eq old_user_count + 1
|
@@ -49,12 +53,14 @@ describe Clearance::UsersController do
|
|
49
53
|
|
50
54
|
context "with valid attributes and a session return url" do
|
51
55
|
it "assigns and creates a user then redirects to the return_url" do
|
52
|
-
user_attributes =
|
56
|
+
user_attributes = FactoryBot.attributes_for(:user)
|
53
57
|
old_user_count = User.count
|
54
58
|
return_url = "/url_in_the_session"
|
55
59
|
@request.session[:return_to] = return_url
|
56
60
|
|
57
|
-
post :create,
|
61
|
+
post :create, params: {
|
62
|
+
user: user_attributes,
|
63
|
+
}
|
58
64
|
|
59
65
|
expect(assigns(:user)).to be_present
|
60
66
|
expect(User.count).to eq old_user_count + 1
|
@@ -67,7 +73,9 @@ describe Clearance::UsersController do
|
|
67
73
|
it "redirects to the configured clearance redirect url" do
|
68
74
|
sign_in
|
69
75
|
|
70
|
-
post :create,
|
76
|
+
post :create, params: {
|
77
|
+
user: {},
|
78
|
+
}
|
71
79
|
|
72
80
|
expect(response).to redirect_to(Clearance.configuration.redirect_url)
|
73
81
|
end
|
@@ -2,6 +2,10 @@ class ApplicationController < ActionController::Base
|
|
2
2
|
include Clearance::Controller
|
3
3
|
|
4
4
|
def show
|
5
|
-
|
5
|
+
if Rails::VERSION::MAJOR >= 5
|
6
|
+
render html: "", layout: "application"
|
7
|
+
else
|
8
|
+
render text: "", layout: "application"
|
9
|
+
end
|
6
10
|
end
|
7
11
|
end
|
data/spec/dummy/application.rb
CHANGED
@@ -4,10 +4,6 @@ require "clearance"
|
|
4
4
|
module Dummy
|
5
5
|
APP_ROOT = File.expand_path("..", __FILE__).freeze
|
6
6
|
|
7
|
-
def self.rails4?
|
8
|
-
Rails::VERSION::MAJOR >= 4
|
9
|
-
end
|
10
|
-
|
11
7
|
I18n.enforce_available_locales = true
|
12
8
|
|
13
9
|
class Application < Rails::Application
|
@@ -18,7 +14,6 @@ module Dummy
|
|
18
14
|
config.action_mailer.delivery_method = :test
|
19
15
|
config.active_support.deprecation = :stderr
|
20
16
|
config.active_support.test_order = :random
|
21
|
-
config.assets.enabled = true
|
22
17
|
config.cache_classes = true
|
23
18
|
config.consider_all_requests_local = true
|
24
19
|
config.eager_load = false
|
@@ -28,13 +23,16 @@ module Dummy
|
|
28
23
|
config.paths["app/views"] << "#{APP_ROOT}/app/views"
|
29
24
|
config.paths["config/database"] = "#{APP_ROOT}/config/database.yml"
|
30
25
|
config.paths["log"] = "tmp/log/development.log"
|
31
|
-
config.secret_token = "SECRET_TOKEN_IS_MIN_30_CHARS_LONG"
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
config.
|
27
|
+
config.paths.add "config/routes.rb", with: "#{APP_ROOT}/config/routes.rb"
|
28
|
+
config.secret_key_base = "SECRET_KEY_BASE"
|
29
|
+
|
30
|
+
if config.active_record.sqlite3.respond_to?(:represent_boolean_as_integer)
|
31
|
+
config.active_record.sqlite3.represent_boolean_as_integer = true
|
32
|
+
end
|
33
|
+
|
34
|
+
if config.respond_to?(:active_job)
|
35
|
+
config.active_job.queue_adapter = :inline
|
38
36
|
end
|
39
37
|
|
40
38
|
def require_environment!
|
data/spec/factories.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
|
1
|
+
FactoryBot.define do
|
2
2
|
sequence :email do |n|
|
3
3
|
"user#{n}@example.com"
|
4
4
|
end
|
5
5
|
|
6
6
|
factory :user do
|
7
7
|
email
|
8
|
-
password 'password'
|
8
|
+
password { 'password' }
|
9
9
|
|
10
10
|
trait :with_forgotten_password do
|
11
|
-
confirmation_token Clearance::Token.new
|
11
|
+
confirmation_token { Clearance::Token.new }
|
12
12
|
end
|
13
13
|
|
14
14
|
factory :user_with_optional_password, class: 'UserWithOptionalPassword' do
|
15
|
-
password nil
|
16
|
-
encrypted_password ''
|
15
|
+
password { nil }
|
16
|
+
encrypted_password { '' }
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -37,6 +37,7 @@ describe Clearance::Generators::InstallGenerator, :generator do
|
|
37
37
|
|
38
38
|
expect(user_class).to exist
|
39
39
|
expect(user_class).to have_correct_syntax
|
40
|
+
expect(user_class).to contain_models_inherit_from
|
40
41
|
expect(user_class).to contain("include Clearance::User")
|
41
42
|
end
|
42
43
|
end
|
@@ -51,6 +52,7 @@ describe Clearance::Generators::InstallGenerator, :generator do
|
|
51
52
|
|
52
53
|
expect(user_class).to exist
|
53
54
|
expect(user_class).to have_correct_syntax
|
55
|
+
expect(user_class).to contain_models_inherit_from
|
54
56
|
expect(user_class).to contain("include Clearance::User")
|
55
57
|
expect(user_class).to have_method("previously_existed?")
|
56
58
|
end
|
@@ -61,9 +63,7 @@ describe Clearance::Generators::InstallGenerator, :generator do
|
|
61
63
|
context "users table does not exist" do
|
62
64
|
it "creates a migration to create the users table" do
|
63
65
|
provide_existing_application_controller
|
64
|
-
|
65
|
-
with(:users).
|
66
|
-
and_return(false)
|
66
|
+
table_does_not_exist(:users)
|
67
67
|
|
68
68
|
run_generator
|
69
69
|
migration = migration_file("db/migrate/create_users.rb")
|
@@ -115,4 +115,30 @@ describe Clearance::Generators::InstallGenerator, :generator do
|
|
115
115
|
end
|
116
116
|
end
|
117
117
|
end
|
118
|
+
|
119
|
+
def table_does_not_exist(name)
|
120
|
+
connection = ActiveRecord::Base.connection
|
121
|
+
|
122
|
+
if connection.respond_to?(:data_source_exists?)
|
123
|
+
allow(connection).to receive(:data_source_exists?).
|
124
|
+
with(name).
|
125
|
+
and_return(false)
|
126
|
+
else
|
127
|
+
allow(connection).to receive(:table_exists?).
|
128
|
+
with(name).
|
129
|
+
and_return(false)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def contain_models_inherit_from
|
134
|
+
contain "< #{models_inherit_from}\n"
|
135
|
+
end
|
136
|
+
|
137
|
+
def models_inherit_from
|
138
|
+
if Rails.version >= "5.0.0"
|
139
|
+
"ApplicationRecord"
|
140
|
+
else
|
141
|
+
"ActiveRecord::Base"
|
142
|
+
end
|
143
|
+
end
|
118
144
|
end
|
@@ -4,14 +4,18 @@ require "generators/clearance/routes/routes_generator"
|
|
4
4
|
describe Clearance::Generators::RoutesGenerator, :generator do
|
5
5
|
it "adds clearance routes to host application routes" do
|
6
6
|
provide_existing_routes_file
|
7
|
+
provide_existing_initializer
|
7
8
|
|
8
9
|
routes = file("config/routes.rb")
|
10
|
+
initializer = file("config/initializers/clearance.rb")
|
9
11
|
|
10
12
|
run_generator
|
11
13
|
|
14
|
+
expect(initializer).to have_correct_syntax
|
15
|
+
expect(initializer).to contain("config.routes = false")
|
12
16
|
expect(routes).to have_correct_syntax
|
13
17
|
expect(routes).to contain(
|
14
|
-
|
18
|
+
'get "/sign_in" => "clearance/sessions#new", as: "sign_in"'
|
15
19
|
)
|
16
20
|
end
|
17
21
|
end
|
@@ -23,7 +23,7 @@ describe User do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
subject { create(:user) }
|
26
|
-
it { is_expected.to validate_uniqueness_of(:email) }
|
26
|
+
it { is_expected.to validate_uniqueness_of(:email).case_insensitive }
|
27
27
|
end
|
28
28
|
|
29
29
|
describe ".authenticate" do
|
@@ -85,6 +85,15 @@ describe User do
|
|
85
85
|
|
86
86
|
expect(user.confirmation_token).to be_nil
|
87
87
|
end
|
88
|
+
|
89
|
+
it "sets the remember token" do
|
90
|
+
user = create(:user, :with_forgotten_password)
|
91
|
+
|
92
|
+
user.update_password("my_new_password")
|
93
|
+
|
94
|
+
user.reload
|
95
|
+
expect(user.remember_token).not_to be_nil
|
96
|
+
end
|
88
97
|
end
|
89
98
|
|
90
99
|
context "with blank password" do
|
@@ -24,7 +24,7 @@ describe Clearance::PasswordStrategies::Blowfish do
|
|
24
24
|
model_instance.salt = salt
|
25
25
|
model_instance.password = password
|
26
26
|
cipher = OpenSSL::Cipher::Cipher.new("bf-cbc").encrypt
|
27
|
-
cipher.key = Digest::SHA256.digest(salt)
|
27
|
+
cipher.key = Digest::SHA256.digest(salt).first(16)
|
28
28
|
expected = cipher.update("--#{salt}--#{password}--") << cipher.final
|
29
29
|
|
30
30
|
encrypted_password = Base64.decode64(model_instance.encrypted_password)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Cookie options" do
|
4
|
+
before do
|
5
|
+
Clearance.configuration.httponly = httponly
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when httponly config value is false" do
|
9
|
+
let(:httponly) { false }
|
10
|
+
describe "sign in" do
|
11
|
+
before do
|
12
|
+
user = create(:user, password: "password")
|
13
|
+
get sign_in_path
|
14
|
+
|
15
|
+
post session_path, params: {
|
16
|
+
session: { email: user.email, password: "password" },
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it { should_have_one_remember_token }
|
21
|
+
|
22
|
+
it "should not have the httponly flag set" do
|
23
|
+
expect(remember_token_cookies.last).not_to match(/HttpOnly/)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when httponly config value is true" do
|
29
|
+
let(:httponly) { true }
|
30
|
+
describe "sign in" do
|
31
|
+
before do
|
32
|
+
user = create(:user, password: "password")
|
33
|
+
get sign_in_path
|
34
|
+
|
35
|
+
post session_path, params: {
|
36
|
+
session: { email: user.email, password: "password" },
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
it { should_have_one_remember_token }
|
41
|
+
|
42
|
+
it "should have the httponly flag set" do
|
43
|
+
expect(remember_token_cookies.last).to match(/HttpOnly/)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def should_have_one_remember_token
|
49
|
+
expect(remember_token_cookies.length).to eq(1),
|
50
|
+
"expected one 'remember_token' cookie:\n#{remember_token_cookies}"
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "CSRF Rotation" do
|
4
|
+
around do |example|
|
5
|
+
ActionController::Base.allow_forgery_protection = true
|
6
|
+
example.run
|
7
|
+
ActionController::Base.allow_forgery_protection = false
|
8
|
+
end
|
9
|
+
|
10
|
+
context "Clearance is configured to rotate CSRF token on sign in" do
|
11
|
+
describe "sign in" do
|
12
|
+
it "rotates the CSRF token" do
|
13
|
+
Clearance.configure { |config| config.rotate_csrf_on_sign_in = true }
|
14
|
+
get sign_in_path
|
15
|
+
user = create(:user, password: "password")
|
16
|
+
original_token = csrf_token
|
17
|
+
|
18
|
+
post session_path, params: {
|
19
|
+
session: session_params(user, "password"),
|
20
|
+
}
|
21
|
+
|
22
|
+
expect(csrf_token).not_to eq original_token
|
23
|
+
expect(csrf_token).to be_present
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def csrf_token
|
29
|
+
session[:_csrf_token]
|
30
|
+
end
|
31
|
+
|
32
|
+
def session_params(user, password)
|
33
|
+
{ email: user.email, password: password, authenticity_token: csrf_token }
|
34
|
+
end
|
35
|
+
end
|