invalid salt (BCrypt::Errors::InvalidSalt) - ruby-on-rails

Since upgraded to Ruby 2.2.0 I get the following message in my tests:
invalid salt (BCrypt::Errors::InvalidSalt)
I didn't find any upgrade notice helping me to understand the problem. I'm using Rails 4.1.8 and Sorcery 0.8.6.
Anybody else having this problem?
MORE Details:
I'm using Sorcery and not Devise. The encrypted data is the password.
It all started in Cucumber tests, in 2 cases:
When I used to send the #user to the mailer to prepare the data for the mails. Here was the code:
UserMailer.passphrase_reset_notification(#user).deliver
Which generated the exception with the message I wrote in the initial message. As a workaround instead of sending the #user I sent the fields I needed and it worked. Here's the new code:
UserMailer.passphrase_reset_notification(#user.name, #user.email).deliver
But the second case is the sign up. It failed in dev and I had to add :salt to user_params to fix it. But it does not fix the thing in the test env.
There's no stack trace, just that one liner message with the lines of my scenario leading to the error.
And I press "Sign up"
invalid salt (BCrypt::Errors::InvalidSalt)
./app/controllers/users_controller.rb:66:in block in create'
./app/controllers/users_controller.rb:64:increate'
./app/controllers/application_controller.rb:120:in scope_current_tenant'
./features/step_definitions/web_steps.rb:53:in/^(?:|I )press "([^"]*)"$/'
features/users/sign_up.feature:149:in `And I press "Sign up"'
I removed the "null: false" for the field "salt" in the user table, as suggested by a community member in a post on a more or less similar issue, it didn't help either.
My main question is still the same: what the Ruby new version (2.2.0) has to do with this? And what might be the other surprises if I upgrade the prod?

I just fixed this. Turned out it had to do with serializing an object with has_secure_password (which uses bcrypt-ruby)
More specifically, something like the following was causing the issue with Sidekiq as it tried to serialize arguments into objects for Redis queueing.
#user = User.new(
:firstname => 'Scott',
:lastname => 'Klein',
:password => 'mypass',
:password_confirmation => 'mypass'
)
#user.save!
# broken
# note that #user.password can still be called here
# and sidekiq will attempt to serialize this whole object using YAML
# and this is the serialization issue that barfs (in the depths of YAML)
UserMailer.delay.new_user_signup(#user)
# fixed
# i just passed the id and then recalled the user record in the mailer class
UserMailer.delay.new_user_signup(#user.id)

I've had similar problem. Investigation made me conclude that it's bcrypt not playing well with Psych (that's the Ruby system library for generating and parsing YAML).
There's an open bcrypt issue now. Waiting for gem author to fix it.

** FIXED **
The problem, at least mine, is fixed. I just upgraded the bcrypt gem from 3.1.
9 to 3.1.10 and it was it! Thanks Oleg to have created an issue on bcrypt account.

Related

Why does BCrypt no longer accept hashes?

Last week I upgrade Fedora to the brand new 28 release, which came with a mongodb upgrade to 3.6. See How to repair mongodb service after an upgrade to Fedora 28? for how I managed to resolve my first problem which was that mongod would no longer start. Now I'm facing an other problem on the Rails application that use this same database.
This most probably is unrelated to the mongodb upgrade, but I thought it might worth providing that context and don't miss a solution for not providing enough of it.
So since the system upgrade any login attempt on this Rails project will fail with a BCrypt::Errors::InvalidHash in Devise::SessionsController#create
error, raised at bcrypt (3.1.11) lib/bcrypt/password.rb:60:ininitialize'`. Analyzing further in a Rails console of the project, it seems any call to this method will fail:
> BCrypt::Password.create('TestPassword')
BCrypt::Errors::InvalidHash: invalid hash
from /home/psychoslave/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bcrypt-3.1.11/lib/bcrypt/password.rb:60:in `initialize'
I tried to bundle uninstall/reinstall bcrypt, and even use the github repository version of the bcrypt gem instead, but it didn't change anything.
Looking at /home/psychoslave/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bcrypt-3.1.11/lib/bcrypt/password.rb:60:ininitialize'`, the problem seems that the hash is not valid.
# Initializes a BCrypt::Password instance with the data from a stored hash.
def initialize(raw_hash)
if valid_hash?(raw_hash)
self.replace(raw_hash)
#version, #cost, #salt, #checksum = split_hash(self)
else
raise Errors::InvalidHash.new("invalid hash")
end
end
And the corresponding test is as follow:
def valid_hash?(h)
h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/
end
The hash itself is created through BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(cost)), which in the platform I use call __bc_crypt(secret.to_s, salt), which seems to be calling bcrypt-3.1.11/ext/mri/bcrypt_ext.c.
More importantly, adding a binding.pry in the valid_hash? method, it's possible to see what the hash value returned for a call to BCrypt::Password.create('TestPassword'), it's actually a rather long string whose start seems usual, but end up with what is most likely misgenerated sequence:
"$2a$10$Eb1f8DSkGh4G1u5GicyTYujBk6SwFXKYCH.nqxapmBlqJ0eFYdX32\x00\x00\x00\x00\xD1F\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00T\xBD\x02\x00\x00\x00\x00\x00\xF1V\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xE2\xB0\x02\x00\x00\x00\x
00\x00AW\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00 \x04\x00\x00\x00\x00\x00\x00\x86\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xB5\xF8\x0E\x00\x00\x00\x00\x00q\xD8\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00…"
I can provide a dump of a whole hash if it might be of any interest (around 32Ko!).
Here is a circumvent solution which make rspec of bcrypt pass all tests successfully again.
This is really a uggly hack while waitting a proper solution, but does the job until then. Just change ~/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bcrypt-3.1.11/lib/bcrypt/engine.rb (path to adapt, of course), line 51 from:
- __bc_crypt(secret.to_s, salt)
+ __bc_crypt(secret.to_s, salt).gsub(/(\n|\x00).*/, '')
That is, trunk the string starting at the first "\x00" or "\n" occurrence, if any.
Credit note: this version of the hack was proposed by Andrey Sitnik, and I replaced the one I proposed here independently, before discovering it.
After that, BCrypt::Password#create will function again:
> BCrypt::Password.create('TestPassword')
=> "$2a$10$YPRnQF3ZihXHpa9kSx7Mpu.j28PlbdwaNs2umSQvAGkS.JJ.syGye"
I had this issue with a (very) old application and BCrypt 3.1.10. Upgrading to 3.1.12 resolved the issue. :)

Weird Bytes Added to Attribute After Save in Rails

We're experiencing an insane bug where seemingly random bytes are some 90% of the time being tacked on to an email field right at the point when the email is being saved. Here's an example of what might occur:
From params: 'user#example.com'
Before validate: 'user#example.com'
After validate: 'user#example.com'
Before save: 'user#example.com'
Value in object after save: 'user#example.com'
Retrieve record just created by id, and fetch id: 'user#example.com\u007f'
Where the heck did that \u007f (the UTF-8 delete character!!!) come from?! That's by far the most common garbage that shows up. Here's a list some other valid byte sequences that have appeared from time to time:
r\u007f
U\u007f
a\u007f
#m$\u007f
Sometimes I get totally garbage bits, I can't tell if there are more bytes than these due to a PG::CharacterNotInRepertoire error:
0xde 0x4d
0xf6 0x7f
0xbc
0xe3 0x6c 0x24
Given the PG::CharacterNotInRepertoire errors that occur, I'm assuming this is happening somewhere immediately before the value is being saved, but outside of the scope of my application code.
Note that this is strangely not happening for any other fields for the user.
Here are all the callbacks that currently touch the email address:
#strip! and #downcase! before validation
Format validation with the regex \A[A-Za-z0-9._%+-]+#(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,20}\z
Some app info:
Ruby v2.2.0
Rails v4.1.8
Postgres v9.3.2
PG v0.17.1
Turns out that pg-ruby < v0.18.0 is incompatible with Ruby v2.2 despite there being no obvious warnings to the contrary...
https://bitbucket.org/ged/ruby-pg/issue/210/crazy-bytes-being-added-to-record
Upgrade now or get bit(s).
Also be aware that if you're using Rails 4.2.0, there is an issue with pg 0.18.* that affects writing binary data. I currently have 4.2.0 monkey-patched with the the patch that will be in 4.2.1. See https://github.com/rails/rails/pull/17680 for details if you are running 4.2.0 with Ruby 2.2 (and thus with pg 0.18.). There may be similar issues on Rails 4.0. and 4.1.* - I haven't figured out which version have the patch, and whether those versions have been released yet.
My monkey-patch for 4.2.0 looks like:
# Should release in Rails 4.2.1
# PostgreSQL, Fix change detection caused by superfluous bytea unescaping
# See https://github.com/rails/rails/pull/17680
if Rails.version == '4.2.0'
module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
class Bytea < Type::Binary # :nodoc:
def type_cast_from_database(value)
return if value.nil?
return value.to_s if value.is_a?(Type::Binary::Data)
PGconn.unescape_bytea(super)
end
end
end
end
end
end
end

why OmniAuth::Strategies::Facebook::NoAuthorizationCodeError is not handled in omniauth on_failure callback?

I am using Omniauth for Rails 3.2.3 application.
I have configured the on_failure callback as show below.
OmniAuth.config.on_failure = Proc.new do |env|
UsersController.action(:omniauth_failure).call(env)
end
This handles the error "OmniAuth::Strategies::CallbackError" but not "OmniAuth::Strategies::Facebook::NoAuthorizationCodeError".
How to handle this error?.Surly I can not use rescue_from as the error happens in Rack level.
Any ideas?
Thank you
Ensure that your Facebook Application is not running in "Sandbox Mode"
I've run into the same issue.
By my humble investigation it seems to be a bug in the strategy implemented in the omniauth-facebook gem (and, at a quick glance in several others). This is a nice write-up on exception handling in omniauth. It says that
... OmniAuth strategies [...], if they encounter a problem, call the method fail! and pass in a symbol describing the problem like :invalid_credentials and the exception they encountered. The fail! method ends up calling OmniAuth.config.on_failure and passing in the Rack environment (after doing a few other things like sticking the exception into the environment...
The same can be inferred from an example the original authors kindly provided. In the source it's not emphasized and I haven't found it in the wiki docs, either (but I may have overlooked).
Many strategies, including omniauth-facebook, currently raises the exception which we cannot catch at app level anymore.
#soundar: I wish that it worked this way, as advertised.
#fastcatch: As you pointed out, the strategies are not handling these failure cases correctly.
#Jon Day: I had to patch the Rack App for 'omniauth-facebook' (1.4.0) in order to get the reporting that I needed:
require 'newrelic_rpm'
module OmniAuth
class Builder < ::Rack::Builder
def call_with_error_handling(env)
begin
call_without_error_handling(env)
rescue OmniAuth::Strategies::Facebook::NoAuthorizationCodeError => error
# Do whatever you'd like when rescuing.. I wanted to report to NewRelic.
NewRelic::Agent.notice_error(error, env)
env
end
end
alias_method_chain :call, :error_handling
end
end
I'm not proud of this code, but it is one way to gain control over that exception ;).

Active Merchant - uninitialized constant ActiveSupport::XmlMini_REXML::StringIO

I have activemerchant 1.16.0 and rails 3.0.5.
I am trying to build a basic code to communicate with PayPal's gateway using active merchant.
if credit_card.valid?
# or gateway.purchase to do both authorize and capture
response = gateway.authorize(1000, credit_card, :ip => "127.0.0.1")
if response.success?
gateway.capture(1000, response.authorization)
puts "Purchase complete!"
else
puts "Error: #{response.message}"
end
else
puts "Error: credit card is not valid. #{credit_card.errors.full_messages.join('. ')}"
end
I get the following error:
/Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/xml_mini/rexml.rb:20:in `parse': uninitialized constant ActiveSupport::XmlMini_REXML::StringIO (NameError)
This error propagates from the gateway.authorize() call.
Any idea what's wrong with my setup?
Thanks.
According to the question, it doesn't work when the code is by itself, but works when require "stringio" is added.
My suspicion is that ActiveMerchant is unit-tested, but for some reason the dependency on StringIO isn't detected by those unit tests, possibly because other parts of the unit testing code indirectly requires stringio.
One thing I recently found out was that require 'yaml' gives you the stringio library as a side effect:
StringIO.new
# NameError: uninitialized constant StringIO
# from (irb):1
require "yaml"
# => true
StringIO.new
# => #<StringIO:0x7fb7d48ce360>
RUBY_VERSION
# => "1.8.7"
and it wouldn't be hard to imagine unit tests for ActiveMerchant (or other parts of Rails) requiring yaml.
However, this is only speculation. I haven't checked, as I don't use Rails.
Andrew Grimm pretty much hit the nail on the head with his original comment on this question. The missing require 'stringio' is indeed the issue. But it is a bug with Rails, more specifically ActiveSupport 3.0.9 (which is where the error seems to be coming from). We can trace it down using the git commit history of rails.
First we need to check out rails and switch to the v3.0.9 tag. If we now look at activesupport/lib/active_support/xml_mini/rexml.rb we see that require 'stringio' is not there. In and of itself this is not significant, but bear with me. We can now switch to the next tag (v3.0.10.rc1), and we'll see that the file hasn't been updated (it is likely that this version of rails will have the same issue). Next tag in line is v3.1.0.beta1, notice that this time around there is a require 'stringio' at the top of the file.
We can check out the commit that brought in this change (this one here from Jan 19th 2011). The commit message says:
fixed a missing require that causes trouble when using AS in a
non-rails env
This would indicate that as long as you're in a rails environment this issue wouldn't surface. So, my guess is something about the environment caused the issue to come up, may have something to do with the fact that the OP says they are using rails 3.0.5, but the error is coming from activesupport-3.0.9. Perhaps the code was called from a rake task that forgot to inherit from :environment (difficult to say without more info). Either way, putting require 'stringio' at the top of the code is definitely the fix, until you can upgrade to Rails 3.1 (once it comes out) at which point the require will no longer be needed.

Problems with ActionMailer: 501 <>: missing or malformed local part

I'm having trouble sending mail using SMTP from a Rails app. I have a Mailer class:
class Mailer < ActionMailer::Base
def newsletter_confirmation(subscription)
recipients "my-valid-email#gmail.com" # this is set to my email
# just for testing purposes and will
# be changed to subscription.email
from "\"my-valid-helo-domain.net\" <noreply#my-valid-helo-domain.net>"
subject "Confirm your subscription"
body :subscription => subscription
end
end
When I try to send the mail, I get a Net::SMTPSyntaxError:
501 <["noreply#my-valid-helo-domain.net"]>: missing or malformed local part
If I comment out the from field, the mail gets delivered ok, but with the from information missing (obviously). Any ideas on what I'm doing wrong?
Thanks.
Edit: I'm using Rails 2.3.2 and Ruby 1.9.1
The error code and the description of the error states that this is an error on the mail server.
I suggest you check the mail servers to pinpoint the error.
When it comes to ActionMailer it is supposed to raise an exception if the configuration parameter raise_delivery_errors is set (default in Production but not in Development I believe), so you can check that one and try to resend if it triggers.
EDIT:
Here is the solution (it's a Ruby/Rails 1.9 bug):
https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2340-action-mailer-cant-deliver-mail-via-smtp-on-ruby-191
and the patch:
https://rails.lighthouseapp.com/projects/8994/tickets/2340/a/104008/action_mailer-ruby-1.9-from-address-fix.patch
It is a known bug. https://rails.lighthouseapp.com/projects/8994/tickets/2340

Resources