Skip to content
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

Fixes #13870 - encrypts specific settings values in db #3230

Merged
merged 1 commit into from
Oct 7, 2016

Conversation

amirfefer
Copy link
Member

@amirfefer amirfefer commented Feb 24, 2016

In the following PR the use case came up.

In order to encrypt a setting value, set its encrypted flag to true:

self.set('root_pass', N_("Default encrypted root password on provisioned hosts"), nil, N_('Root password')), nil, {:encrypted => true})

@@ -0,0 +1,75 @@
module EncryptField
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Encryptable module encrypts the whole attribute (column), while in some cases there is a need to encrypt a specific field (instance variable). such use cases can be found in settings, and in parameters.
hence encryptable module has splitted into two modules, the first one is encrypt_field, which can be included to models in case of specific fields encryption, and the encryptable which keeps the logic for attribute encryption.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick, can you call this EncryptString or similar? "field" has a similar meaning to "attribute" to me, so I was confused for a while with the terminology.

@xprazak2
Copy link
Contributor

Not sure where it comes from, but I get additional characters attached to my desired setting value, when I try to change it through setter:

@amirfefer
Copy link
Member Author

@domcleal An encrypted flag was added to Setting table, instead of using type attribute.

@amirfefer
Copy link
Member Author

[test]

@domcleal
Copy link
Contributor

The failures are on every combination as DB migration from clean is failing, please take a look at the errors.

@domcleal
Copy link
Contributor

Unit test failures remain, please take a look.

Please remember to comment on PRs when you change them, see https://groups.google.com/d/msg/foreman-dev/poyjF8Ig5UE/jaFyZVGOsEUJ.

@amirfefer
Copy link
Member Author

@domcleal Tests are failing because unrelated issue in host#edit.

@@ -100,11 +101,13 @@ def self.method_missing(method, *args)

def value=(v)
v = v.to_yaml unless v.nil?
v = encrypt_field(v) if defined? encrypted and encrypted
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer has_attribute?(:encrypted) perhaps? A comment to say why you're performing this check would be useful - I'm assuming it's to enable DB migrations on older versions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer && in an expression instead of and.

if change.is_a? Array
change.map! {|c| c.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX) ? _("[encrypted]") : c}
else
audited_changes[name] = _("[encrypted]") if change.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX)
Copy link
Contributor

@domcleal domcleal Sep 30, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using _() in this context will store the translated message in the database, so it'll be stored in the language of whoever made the change instead of whoever is viewing it.

I think perhaps you want to use _N('[encrypted]') here to only extract it, store the English and then call _(db_value) in the helper for display purposes (when db_value == '[encrypted]').

self.audited_changes.each do |name,change|
next if change.nil? || change.to_s.empty?
if change.is_a? Array
change.map! {|c| c.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX) ? _("[encrypted]") : c}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, storing a translated string instead of English

@@ -13,7 +13,7 @@ def id_to_label(name, change)
when /.*_id$/
name.classify.gsub('Id','').constantize.find(change).to_label
else
change.to_s
change.to_s.include?(EncryptValue::ENCRYPTION_PREFIX) ? _("[encrypted]") : change.to_s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that's better, but there aren't any tests for the functionality - please add to test/models/concerns/audit_extensions_test.rb.

Copy link
Contributor

@domcleal domcleal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i18n issue with the stored string, and missing unit test for the audit model changes.

@amirfefer
Copy link
Member Author

@domcleal I fixed i18n issue , and added a unit test into Audit model extension.

if change.is_a? Array
change.map! {|c| c.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX) ? N_("[encrypted]") : c}
else
audited_changes[name] = N_("[encrypted]") if change.to_s.start_with?(EncryptValue::ENCRYPTION_PREFIX)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does [encrypted] get translated in the UI? My last comment here suggested doing it in a UI helper, but I can't see that in this PR. (See #3230 (comment))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just forgot to commit the changes in audits_helper.

assert setting.save
end
a = Audit.where(auditable_type: 'Setting')
assert_equal N_("[encrypted]"), a.last.audited_changes["value"][1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove N_() from here, no need to extract a string in a test.

@domcleal
Copy link
Contributor

domcleal commented Oct 6, 2016

Thanks, one last thing: the encrypted column itself is being audited so you see it change when this patch is applied, but since it's an internal field it should be excluded. Add it to the audited :exclude list in app/models/settings.rb please.

@amirfefer
Copy link
Member Author

@domcleal I inserted encrypted field to the audited :except list in setting.

@domcleal domcleal merged commit b5eefd9 into theforeman:develop Oct 7, 2016
@domcleal
Copy link
Contributor

domcleal commented Oct 7, 2016

Merged, thanks @amirfefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants