[yast-devel] An interesting Ruby exercise for a Friday
As part of the re-implementation of the Encrypted LVM proposal I needed to store a password inside and object, but I didn't want to simply do class SomeClass attr_accessor :name attr_accessor :password end because I felt it was relatively easy to leak the password to the logs accidentally just by doing log.info "A something object #{an_instance_of_that_class.inspect}" Redefining #to_s and #inspect for every class containing a password is cumbersome and error prone. So I decided to create an alternative to attr_accessor with the same behavior but with enhanced protection against leaks. So you can do class SomeClass include Yast::SecretAttributes attr_accessor :name secret_attr :password end And all calls to #to_s, #inspect are safe. Even using formatters like pretty_print or awesome_print should be safe. Here is a gist with two possible implementations. I would go for the first one because is "less magic". But I also wanted to share the second alternative because I consider it to be an interesting Ruby exercise (redefining methods at instance level). https://gist.github.com/ancorgs/3a9c08313cc0ed52cc759ac94b21fa56 Do you like it enough to be included in yast2 or should I keep it just in the y2storage namespace? Any obvious drawback in the implementation? I'm writing RSpec tests right now, before you ask. Cheers -- Ancor González Sosa YaST Team at SUSE Linux GmbH -- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
On 02/10/2017 02:06 PM, Ancor Gonzalez Sosa wrote:
Any obvious drawback in the implementation?
I'm writing RSpec tests right now, before you ask.
Hi, This really sounds cool for Friday hacking ;) My only question here is: Are we really the first ones to be solving such issue? If yes, how comes so? If no, then some generic solution probably already exists. Thx Lukas -- Lukas Ocilka, Systems Management (Yast) Team Leader SLE Department, SUSE Linux Sent from my Zarma Haka 3.0 -- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
On 02/10/2017 02:26 PM, Lukas Ocilka wrote:
On 02/10/2017 02:06 PM, Ancor Gonzalez Sosa wrote:
Any obvious drawback in the implementation?
I'm writing RSpec tests right now, before you ask.
Hi,
This really sounds cool for Friday hacking ;) My only question here is: Are we really the first ones to be solving such issue? If yes, how comes so? If no, then some generic solution probably already exists.
Of course I did some research before about patterns to solve this in general and in Ruby. That's how I found this https://github.com/jordansissel/software-patterns/tree/master/dont-log-secre... which I used as an inspiration and which allowed me to discover awesome_print. So I also tested my both solutions with to_s, inspect, pretty_print and awesome_print. I also checked the Ruby on Rails solution, which works at logger level, instead of at class level. I prefer ours and I doubt something similar to the Rails solution would make sense for us. Cheers. -- Ancor González Sosa YaST Team at SUSE Linux GmbH -- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
On 02/10/2017 02:06 PM, Ancor Gonzalez Sosa wrote:
And all calls to #to_s, #inspect are safe. Even using formatters like pretty_print or awesome_print should be safe.
Ah, and I found one little case where redefining #to_s might cause some problems: ```life When you really want to use it for something else than logging ``` Thx Lukas -- Lukas Ocilka, Systems Management (Yast) Team Leader SLE Department, SUSE Linux Sent from my Zarma Haka 3.0 -- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
On 02/10/2017 02:31 PM, Lukas Ocilka wrote:
On 02/10/2017 02:06 PM, Ancor Gonzalez Sosa wrote:
And all calls to #to_s, #inspect are safe. Even using formatters like pretty_print or awesome_print should be safe.
Ah, and I found one little case where redefining #to_s might cause some problems:
```life When you really want to use it for something else than logging ```
As long as you want to access that value explicitly, #to_s will work exactly as expected. For example. class TheClass include Y2Storage::SecretAttributes attr_accessor :name secret_attr :password end one_object = TheClass.new one_object.name = "Aa" one_object.password = 42 one_object.password # => 42 one_object.password.to_s # => "42" one_object.send(:password) # => 42 one_object.send(:password).to_s # => "42" So if you really want to use #to_s for that attribute, it will work with no surprises. BUT the class saves you from revealing that value in an indirect way (i.e. via inspection of the instance attributes). For example: one_object.to_s # => "#<TheClass:0x000000026bcc98>" - This is the default behavior one_object.inspect # => "#<TheClass:0x00000000c7cbf8 @password=<secret>, @name=\"Aa"\">" Even more: one_object.instance_variables.each do |var| puts "#{var}: #{one_object.instance_variable_get(var)}" puts "#{var} to_s: #{one_object.instance_variable_get(var).to_s}" end Will print @name: Aa @name to_s: Aa @password: <secret> @password to_s: <secret> So the mixin never puts itself in your way, it's just in the way of lurkers who want to inspect the internal state of your objects directly. And that's exactly the problem it tries to avoid. By their own nature, methods used for logging like #inspect don't use your setters and getters to access your inner state (as you and every well-educated piece of software should do). Those methods that violate the uniform access principle are the only ones affected by the mixin. Other than that, .secret_attr is 100% equivalent to .attr_accessor. Cheers. -- Ancor González Sosa YaST Team at SUSE Linux GmbH -- To unsubscribe, e-mail: yast-devel+unsubscribe@opensuse.org To contact the owner, e-mail: yast-devel+owner@opensuse.org
participants (2)
-
Ancor Gonzalez Sosa
-
Lukas Ocilka