Skip to content

Commit 179fd6b

Browse files
authored
Merge pull request #1109 from texpert/fix-updated-ajax
Fix updated_ajax action to permit only legit params
2 parents 4b5ce85 + d9036f0 commit 179fd6b

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed

app/controllers/camaleon_cms/admin/users_controller.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,15 @@ def update
5252
def updated_ajax
5353
@user = current_site.users.find(params[:user_id])
5454
update_session = current_user_is?(@user)
55-
@user.update(params.require(:password).permit!)
56-
render inline: @user.errors.full_messages.join(', ')
55+
attrs = params.require(:password).permit(%i[password password_confirmation])
56+
@user.update(password: attrs.require(:password), password_confirmation: attrs.require(:password_confirmation))
57+
58+
return render inline: @user.errors.full_messages.join(', '), status: :unprocessable_entity if @user.errors.any?
59+
5760
# keep user logged in when changing their own password
5861
update_auth_token_in_cookie @user.auth_token if update_session && @user.saved_change_to_password_digest?
62+
rescue ActionController::ParameterMissing => e
63+
render inline: "ERROR: #{e.class.name}, #{e.message}", status: :bad_request
5964
end
6065

6166
def update_auth_token_in_cookie(token)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe 'updated_ajax request', type: :request do
6+
init_site
7+
8+
let(:current_site) { Cama::Site.first.decorate }
9+
let(:current_user) { create(:user_admin, site: current_site, password: 'secret', password_confirmation: 'secret') }
10+
11+
before do
12+
allow_any_instance_of(CamaleonCms::AdminController).to receive(:cama_authenticate)
13+
allow_any_instance_of(CamaleonCms::Admin::UsersController).to receive(:validate_role).and_return(true)
14+
end
15+
16+
context 'when receiving correct params' do
17+
it "updates user's password" do
18+
expect(current_user.authenticate('secret')).to be_truthy
19+
expect(current_user.authenticate('new password')).to be_falsey
20+
21+
patch "/admin/users/#{current_user.id}/updated_ajax",
22+
params: { password: { password: 'new password', password_confirmation: 'new password' } }
23+
24+
expect(response.status).to eql(204)
25+
expect(response.body).to eql('')
26+
expect(current_user.reload.authenticate('secret')).to be_falsey
27+
expect(current_user.reload.authenticate('new password')).to be_truthy
28+
end
29+
end
30+
31+
context 'when receiving incorrect params' do
32+
context 'when wrong password confirmation' do
33+
it "doesn't update user's password and return error" do
34+
expect(current_user.authenticate('secret')).to be_truthy
35+
36+
patch "/admin/users/#{current_user.id}/updated_ajax",
37+
params: { password: { password: 'new password', password_confirmation: 'old password' } }
38+
39+
expect(response.status).to eql(422)
40+
expect(response.body).to eql("Password confirmation doesn't match Password")
41+
expect(current_user.reload.authenticate('secret')).to be_truthy
42+
end
43+
end
44+
45+
context 'when missing password confirmation' do
46+
it "doesn't update user's password" do
47+
expect(current_user.authenticate('secret')).to be_truthy
48+
49+
patch "/admin/users/#{current_user.id}/updated_ajax", params: { password: { password: 'new password' } }
50+
51+
expect(response.status).to eql(400)
52+
expect(response.body).to start_with(
53+
'ERROR: ActionController::ParameterMissing, param is missing or the value is empty'
54+
)
55+
expect(response.body).to include('password_confirmation')
56+
expect(current_user.reload.authenticate('secret')).to be_truthy
57+
expect(current_user.reload.authenticate('new password')).to be_falsey
58+
end
59+
end
60+
61+
context 'when passing unpermitted params' do
62+
it 'ignores the unpermitted param' do
63+
expect(current_user.authenticate('secret')).to be_truthy
64+
65+
# Changing this to false, because the receiver is not only yielded to the blocks, but also passed as an
66+
# unexpected additional argument to the `originall.call`
67+
RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks = false
68+
69+
allow_any_instance_of(CamaleonCms::User).to receive(:update).and_call_original
70+
71+
expect_any_instance_of(CamaleonCms::User)
72+
.to receive(:update).with(password: 'new password', password_confirmation: 'new password')
73+
74+
patch "/admin/users/#{current_user.id}/updated_ajax",
75+
params: { password: { password: 'new password', password_confirmation: 'new password', role: 'admin' } }
76+
77+
expect(response.status).to eql(204)
78+
expect(response.body).to eql('')
79+
expect(current_user.reload.authenticate('secret')).to be_falsey
80+
expect(current_user.reload.authenticate('new password')).to be_truthy
81+
82+
# returning the default configuration
83+
RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks = false
84+
end
85+
end
86+
end
87+
end

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
ENV['RAILS_ENV'] ||= 'test'
22

3+
require 'pathname'
34
CAMALEON_CMS_ROOT = Pathname.new(__FILE__).join('../..')
45

56
require File.expand_path('dummy/config/environment.rb', __dir__)

0 commit comments

Comments
 (0)