Rails 5 filtered parameters - ruby-on-rails

I am migrating my 4.2 app into Rails 5 and I run into a strange problem. When I try to log in via this:
<%= password_field_tag :password %>
I got [FILTERED] log in server console, but I got params[:pasword] => "*****" in controller. Which is of course not matching password (I am using BCrypt).
password encrypting:
def encrypt_password(pass)
BCrypt::Engine.hash_secret(pass, password_salt)
end
When I pass string "*****" into this method I got the same result as if I pass params[:password] there, which means the controller doesn't know about inserted password but gets only 5 asterisks.
If I try this on my master branch with Rails 4.2.7 then in controller I can correctly see inserted password (in log there is "[FILTERED]" correctly).
Do I miss some new feature about filtering parameters in Rails 5???
EDIT:
I tried
render plain: params.to_yaml
I got:
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
utf8: "✓"
authenticity_token: 6/qK4IYcTL3lDTLNEICMmrcBhR5FJy6r3QNN5hYXNQTOqrdwtcX5aye4wN3AIz6PSmsMSf6V7/z8fmUo7KUXyQ==
login: doktor
password: "*****"
commit: Přihlaš
permitted: false

Related

Rails system test w/ Capybara RackTest raises ActiveSupport::MessageVerifier::InvalidSignature

I have a typical Rails model form with a file attachment selector allowing multiple attachments. It works fine in development, but during a system test, raises an ActiveSupport::MessageVerifier::InvalidSignature exception.
Rails 7.0.2.2
capybara 3.36.0
rack-test 1.1.0
The model has_many_attached :photos.
The form is using form_with and multipart: true.
The HTML source looks correct.
In development, manually using the form with 0 or any file attachments works as expected.
In my system test, I am using the rack_test driver.
test "creating a quote request" do
visit new_quote_request_path
fill_in "First name", with: 'FAKE FIRST'
# ...
click_on "Submit"
assert_text "Success"
end
In the controller, my canonical param-permitting method looks like:
def quote_request_params
params.require(:quote_request).permit(:first_name, :last_name, :email,
:phone_number, :shipping, :promo_code, :description, :item_type_id, :brand_id,
photos: [])
end
My controller create method is typical...
def create
#quote_request = QuoteRequest.new(quote_request_params)
respond_to do |format|
# ...
In the system test, the call of QuoteRequest.new(quote_request_params) raises an ActiveSupport::MessageVerifier::InvalidSignature exception.
With a breakpoint in place, I can see that the quote_request_params looks like:
#<ActionController::Parameters {"first_name"=>"FAKE FIRST",
"last_name"=>"FAKE LAST", "email"=>"fake#fake.com",
"phone_number"=>"5415555555", "shipping"=>"1", "promo_code"=>"",
"description"=>"Fake quote request description.",
"item_type_id"=>"980190962", "brand_id"=>"980190962",
"photos"=>[
"",
"#<Capybara::RackTest::Form::NilUploadedFile:0x000000010dae35b8>"
]} permitted: true>
And it seems Capybara is doing its default behavior of attaching a 'nil file' for the multipart form.
Why is the test raising an ActiveSupport::MessageVerifier::InvalidSignature exception?
This is an issue with Rails 7 and rack-test. It can temporarily be solved by putting the following in config/environments/test.rb:
config.active_storage.multiple_file_field_include_hidden = false
Refer to the rack-test issue for more details.

Improper indentation in converting ruby hash to yaml

I am trying to convert ruby hash object to YAML format using YAML.dump(obj) but I am getting improper indentation even after using dump options.
I have below executable ruby script :
#!/usr/bin/ruby
require "yaml"
require "erb"
context_path = ARGV[0]
context = YAML.load_file(context_path)['context']
def get_yaml(obj)
YAML.dump( obj['imports']['external_repositories']['credentials'] ).sub(/.*?\n/,'')
end
The value of - obj['imports']['external_repositories']['credentials'] is
{"iacbox"=>{"basic"=>{"name"=>"", "password"=>""}}, "nexus"=>{"basic"=>{"name"=>"cpreader", "password"=>"swordfish"}}}
Note : I used the sub method to remove "---" at the start of the output
The ERB template calls the above get_yaml method as :
credentials:
<%= get_yaml( context ) %>
The output that is coming is :
credentials:
iacbox:
basic:
name: ''
password: ''
nexus:
basic:
name: cpreader
password: swordfish
while I am expecting the output as :
credentials:
iacbox:
basic:
name: ''
password: ''
nexus:
basic:
name: cpreader
password: swordfish
How can I get the expected output from a dump?
I think the easiest thing for you to do here is just put the credentials key also in the Hash, i.e. change your template snippet so that it is one line:
<%= get_yaml( context ) %>
And change your get_yaml method to be:
def get_yaml(obj)
YAML.dump({'credentials' => obj['imports']['external_repositories']['credentials']})
.sub(/.*?\n/,'')
end
If that doesn't work for you, for example, if you have additional keys underneath the credentials key that you haven't mentioned, you could also do something like this:
def get_yaml(obj)
YAML.dump(obj['imports']['external_repositories']['credentials'])
.sub(/^---\n/,'')
.gsub(/\n/m,"\n ")
end
Where gsub(/\n/m,"\n ") replaces all newlines with a newline plus two spaces.

How do I generate a CSRF token from the Rails console?

I'm trying to make an authenticated post request, and I need the CSRF. When I log in, it isn't generating the _csrf_token for some reason:
2.0.0p247 :126 > app.post '/community_members/login', {"refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}
=> 302
2.0.0p247 :127 > app.session
=> {"warden.user.refinery_user.key"=>[[56], "$2a$10$gr/rTcQfuXnes1Zml3qOPu"], "session_id"=>"f77d89cef9ff1710890f575b479bb690"}
I tried app.session[:_csrf_token] ||= SecureRandom.base64(32) before login, but it is always deleted. I also tried to get the login form first, but _csrf_token is still not set.
2.0.0p247 :133 > app.get '/community_members/sign_in'
2.0.0p247 :134 > app.response # authenticity_token is burried in the raw HTML
2.0.0p247 :136 > app.post '/community_members/login', {"refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}
2.0.0p247 :137 > app.session
=> {"warden.user.refinery_user.key"=>[[56], "$2a$10$gr/rTcQfuXnes1Zml3qOPu"], "session_id"=>"c2c564229e55b81ca788788558d7d11a"}
How do I manually generate the token to pass to the post request?
Oh ok, I think I need to submit the authenticity_token (that is set in the session after GETing the login form) to the login form, then it puts it in the session permanently! This worked:
app.post '/community_members/login', {'authenticity_token'=>'GfT5GtcUmYQ927oNQmh2MR0NKQucGSx8mtMg3Ph9kXw=', "refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}
Here is a full example: https://stackoverflow.com/a/23899701/148844
I felt like using Nokogiri to parse the response was a little heavy so I wrote a simple regex to pull the authenticity token out of the response.
app.get '/api_with_form'
authenticity_token = app.response.body.match(/<[^<]+authenticity_token[^>]+value="([^"]+)"[^>]+>/)[1]
I'm using this to log in
app.get '/users/sign_in'
authenticity_token = app.response.body.match(/<[^<]+authenticity_token[^>]+value="([^"]+)"[^>]+>/)[1]
app.post '/users/sign_in', 'user[email]' => 'my_username', 'user[password]' => 'my_password', authenticity_token: authenticity_token
Unless you load the page before you do app.post, there is no CSRF token generated to begin with. Manually generating a new one will not help because it won't match what is stored on the server, which is likely to be some null value.
You need to load the page, parse out the CSRF token, and then use that one.
Alternately, you can load the form, try to read the CSRF token out of app.session[:_csrf_token] and use that.
I use these commands in rails console:
app_controller = ActionController::Base::ApplicationController.new
app_controller.request = ActionDispatch::Request.new({})
app_controller.send(:form_authenticity_token)

Devise Password Reset Issue Rails 4

I'm using Devise for authentication with a Rails 4 app and am having issues with the password reset. Locally, everything works fine, when I paste the reset link in (i.e. localhost:3000/users/password/edit?reset_password_token=e_f3ZpqrE_rTBZmKJk_E) it works as expected.
On Heroku however, Devise seems to not even notice the :reset_password_token param, and automatically redirect to /users/signin with the notice "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
Here's is an example of the link that is being generated: http://mysite.io/users/password/edit?reset_password_token=anzYNreZEcz4-dtZy5Uf
I even overrode the assert_reset_token_passed method in my own controller to check if params[:reset_password_token] was actually blank, and for some reason it is, rails is not pulling this out of the url. Here's my modified method:
def assert_reset_token_passed
logger.info params[:reset_password_token] #This is blank somehow
if params[:reset_password_token].blank?
set_flash_message(:alert, :no_token)
redirect_to new_session_path(resource_name) #This is where the redirect happens
end
end
Any help would be much appreciated.
I was having the exact same issue. The fix for me was to update the config.action_mailer.default_url_options in production.rb to include the full host (in my case 'www.mydomain.com' vs 'mydomain.com').
To clarify, it used to be
config.action_mailer.default_url_options = { :host => 'mydomain.com' }
and now it's
config.action_mailer.default_url_options = { :host => 'www.mydomain.com' }

Lost values after switching email sending from AR_Mailer to DelayedJob

I've been using AR_Mailer for about 6 months without ever running into problems. I recently added DelayedJob for some administrative background jobs. Since DelayedJob also handles emails very well (thanks to DelayedMailer gem) I completely removed AR_Mailer from my application.
Everything works perfectly except this email. The password that is generated automatically is now lost.
#app/models/notifier.rb
def activation_instructions(user)
from default_email
#bcc = BACK_UP
#subject = "Activation instructions"
recipients user.email
sent_on Time.now
body :root_url => root_url, :user => user
end
#app/views/notifier/activation_instructions.erb
Thanks for signing up.
Your password is <%=#user.password-%>. For security reasons please change this on your first connection.
[....]
Any idea on why this bug occurs?
Thanks!
Configuration: Rails 2.3.2 & DelayedJob 2.0.4
I found out where the problem was. I looked in the database at the entry created in the delayed_jobs table:
--- !ruby/struct:Delayed::PerformableMethod
object: LOAD;Notifier
method: :deliver_activation_instructions!
args:
- LOAD;User;589
The user parameter is reloaded from the database by delayed_job before sending the email. In that case, the password is lost because it's not stored in the database.
So I've updated the code in order to pass explicitly the password:
#app/models/notifier.rb
def activation_instructions(user, password)
from default_email
#bcc = BACK_UP
#subject = "Activation instructions"
recipients user.email
sent_on Time.now
body :root_url => root_url, :user => user, :password => password
end
#app/views/notifier/activation_instructions.erb
Thanks for signing up.
Your password is <%=#password-%>. For security reasons please change this on your first connection.
[....]
Hope this helps other too!

Resources