New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
attr_encrypted is incompatible with the upcoming Rails 7 ActiveRecord::Encryption API #192
Comments
It looks like this bit will work since the methods will be defined, but the gemspec is defensive with |
Here's what we did to make this work. We've back ported the Rails encryption infrastructure into Rails 6.1 as we were doing some similar work on encrypted structures and this being merged for Rails 7 was a happy coincidence that we decided to take advantage of. We migrated devise-two-factor to the new encryption mechanism without issue using this patch: master...cybersecuricy:securicy-activerecord-encryption-rails-6-1 We've only tested this with our back port and Rails 6.1, but it has been working without issue so far. |
Just checking if there's any movement on this one, it looks like carbidesecure@e409e20 might be suitable to drop in place? |
👀 |
I tried using the securicy-fixed-rails-7 and it won't save the otp_secret. User.generate_otp_secret works but it won't save the user attribute. No error but when I check the value of user.otp_secret it is nil |
@jason-hobbs hm, it's working for us, and we've been using our securicy-fixes-rails-6-1 branch in production using an extraction of the Rails 7 encryption infrastructure for Rails 6.1 for months now. I just checked on our Rails 7 branch and our
The specs also all run in our securicy-fixes-rails-7 branch.
|
It is really strange, rails 6 works fine but here are my steps: It looks like the rails6 version is using encrypted_otp_secret: the rails7 version seems to be ignoring all encrypted* fields |
Could it be because of old bcrypt dependency? here is my devise.rb file:
Here is the top of my user.rb model:
|
@jason-hobbs okay, so for existing projects, there is some legwork you'll have to do. First off, you'd need to migrate the existing Something like the following would work: class MigrateOtpCodes < ActiveRecord::Migration[7.0]
def up
add_column :users, :otp_secret, :text
User.reset_column_information
User.where.not(encrypted_otp_secret: nil).find_each do |user|
user.update!(
otp_secret: Encryptor.decrypt(
Base64.decode64(user.encrypted_otp_secret),
key: <the encryption key you used for devise-two-factor>,
iv: user.encrypted_otp_secret_iv.unpack1('m'),
salt: user.encrypted_otp_secret_salt.slice(1..-1).unpack1('m')
)
)
end
end
def down
remove_column :users, :otp_secret
end
end That will migrate the existing data into the new Rails 7 encryption format. At that point you can drop the old encrypted columns and you're done. Note that you need to include the This worked for us, and has been working in both Rails 6.1 using the aforementioned extraction gem I posted above and appears to be working in Rails 7, which we are in the process of evaluating for eventual use. |
That worked perfectly! Thank you so much! I will use your branch for now and hopefully they merge it soon! |
@dark-panda this is perfect. Do you mind opening a PR for this? |
I could write up a PR for this, but I think some documentation would have to be added to include the details on migrating your existing data from Rails pre-7.0, as per the migration code above. It would perhaps help to have a generator for a migration that would help guide a migration. There would also likely have to be some kind of major version upgrade -- as it exists now, my branch does not care about backwards compatibility at all, and works only with Rails 7+. Some good documentation would have to be in place to make sure people realize this, so if I were to go a head with a PR we should discuss some of these issues so we can work out how to move forward with Rails 7+. |
@dark-panda are you in touch with the guys from Tinfoil about this or working on a PR? If not, I can see if I can give it a shot. If you are working on it, let me know if I can help out! |
I'm having the same issue as you with the @jason-hobbs – I'm wondering if you can help. Mine is a brand new implementation of 2FA so I don't need to handle any legacy token migration. However, the encrypted attr I am wondering about this:
Where does Currently I'm just doing this:
where |
Ah, so I indeed needed to modify it to this to get it working:
|
@Jonakemon i haven’t been in touch with anyone besides what’s here in this thread. Any and all help and discussion would be appreciated, as there would need to be decisions made about proceed, backwards compatibility, migrations, etc. These sorts of things are perhaps outside of what I’m capable of deciding without some discussion and direction. What I can say is that the patches provided have been running in production for us for over 8 months or so now without issue, but ours is but a single use-case and some care needs to be given to roll it all out to a wider audience. |
IMO it's more important that this gem works with the latest version of rails than that it has documentation about migration, etc. The major version can be bumped according to semver, and the migration procedure docs can be added later, for example (with a quick note and link to this thread in the interim). But I'm not in any way associated with the project 🤷 FWIW I'm using https://github.com/cybersecuricy/devise-two-factor/tree/securicy-fixes-rails-7 (rebased onto the latest master), although not yet in prod. |
Hi there, I ran into various issues migrating from rails 6.1 to 7.0 as well. I've tried the migration mentioned here #192 (comment) and it worked with this branch: https://github.com/cybersecuricy/devise-two-factor/tree/securicy-fixes-rails-7 However, I was not able to replicate the success across multiple other environments, here's what seemed to work for me in the rails console: # Given small amounts of users of 250
UserStruct = Struct.new(:id, :otp_secret, keyword_init: true)
users_secret = User.where.not(encrypted_otp_secret: nil).map do |user|
UserStruct.new(id: user.id, otp_secret: user.otp_secret)
end
# Save data just in case
# data = Marshal.dump(users_secret)
# users_secret = Marshal.load(data)
# Give you have a broken migration that currently fails
# Migrate up 20220304142415
migration_version = "20220304142415"
ActiveRecord::Migration.add_column :users, :otp_secret, :text
ActiveRecord::SchemaMigration.create!(version: migration_version)
# Migrate down
# ActiveRecord::Migration.remove_column :users, :otp_secret
# ActiveRecord::SchemaMigration.find_by(version: migration_version).destroy
User.reset_column_information
users_secret.each do |user_secret|
user = User.find_by_id(user_secret.id)
user.update!(otp_secret: user_secret.otp_secret)
rescue
pp "User update failed: #{user_secret.id}, secret: #{user_secret.otp_secret}"
end That being done, am I compromising anything doing this, or is it fine? Excluding the fact it's not a good idea to run schema/ data migration from console 🙈 |
What about making changes to attr_encrypted gem to make it compatible with activerecord 7? |
There's a branch by Cybersecuricy that works with Rails 7, but it doesn't include the recent CVE fix. I've commented on the recent PR for Rails 7 support, but I don't know if that will get seen. #204 |
@r7kamura it works for me |
On the other hand, if rails/AC supports encrypted attrs natively now, perhaps it's simply worth using that functionality and removing the dependency on attr-encrypted altogether? |
Anybody using the https://github.com/cybersecuricy/devise-two-factor/tree/securicy-fixes-rails-7 fork who want to switch to mainline devise-two-factor version 5.0 again (which merged a similar/improved PR for the same functionality) In your model you probably call |
Both the upcoming Rails 7
ActiveRecord::Encryption
module andattr_encrypted
use a class attribute namedencrypted_attributes
which leads to all sorts of issues when you useattr_encrypted
on any Rails 7 model.I have a proof-of-concept which changes
devise-two-factor
to use the new Rails 7 API and dropsattr_encrypted
entirely. For the POC, I've changed thedevise-two-factor
interface a little to use things like the Rails 7 encryption options sort of configuration for consistency, but as a result the POC is incompatible with the current configuration options interface, but perhaps it might be a useful starting point for a more fleshed out solution.The text was updated successfully, but these errors were encountered: