Forum: Ruby on Rails Agile Dev w/Rails, pp.128-129 Hashing Passwords

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
41e1579600683eed6c00af9a425268e6?d=identicon&s=25 epfrederick (Guest)
on 2005-11-15 23:14
(Received via mailing list)
Demo: In Task F, Iteration F1 (near File 54 marker), in the Rails book
by D. Thomas.

He suggests handling password hashing by using the AR callbacks.

<snip>
attr_accessor :password
<snip>
def before_create
  self.hashed_password = User.hash_password(self.password)
end

Is this simply to illustrate callbacks? Would it not be easier to
create a virtual accessor:

def password=(plain)
  hashed_password = User.hash_password(plain)
end

I don't like the idea of that transient plain-text field and extra
callback methods.

I'm just wondering if I'm missing something about the whole
form->action->AR->save cycle where this alternate technique would be
worse than the callback method.

I can answer my own question here in that it would be hard to enforce
password policies without a transient plain-text version to validate
against; however, the question remains: what is the best practice?

Thanks
2ee1028723473faa763884e902ce3366?d=identicon&s=25 thiessen (Guest)
on 2005-11-16 06:43
(Received via mailing list)
Edward Frederick <epfrederick@...> writes:

> Is this simply to illustrate callbacks? Would it not be easier to
> create a virtual accessor:
> ...
> I'm just wondering if I'm missing something about the whole
> form->action->AR->save cycle where this alternate technique would be
> worse than the callback method.
>
> I can answer my own question here in that it would be hard to enforce
> password policies without a transient plain-text version to validate
> against; however, the question remains: what is the best practice?

I tried several ways of accomplishing the same goal; after some
trial-and-error,
I settled on the "virtual" approach you describe as being the most
simple to
understand (and so theoretically the most maintainable).  Other than
complexity,
I don't see that one method has any benefit over the other.

As you suggest in your comment about enforcing password policies, you
have to
add a little bit more code to make the virtual attribute approach work
with form
validation.  Here's what I did (inside my model):

def password=(password)
  @password = password

  salt = random_string(10)
  hash = Digest::SHA1.hexdigest(salt + password)

  self.password_salt = salt
  self.password_hash = hash
end

def password
  return @password if @password
  return 'password' if not self.password_hash.blank?
end

def password_is?(password)
  return Digest::SHA1.hexdigest(self.password_salt + password) ==
self.password_hash
end

Basically, my password= is the same as yours, with the addition of doing
the
salt stuff and setting an instance variable to the plain-text password.
The
instance variable is never saved, so it is indeed "transient", as you
suggest,
but it's available for the password method to access for purposes of
form
validation.

Since we don't save the plain-text password we have to come up with
*something*
to return when the password method is called and the @password instance
variable
is no longer available--so I return the string "password": it will pass
my field
validations, so it serves nicely. You could return the password hash,
but it's
longer than the length limit I have on the password field in my
validations. Set
up this way I can put all my password rules in the model as field
validations,
and everything automagically works just the way you would want it to.

The third method is what I use to actually check whether the password a
user
types is correct or not; I decided to encapsulate it in the model so
none of the
rest of my code needs to know anything about salts or any other
implementation
details.

--Forrest
5d06917e13b29bcff1c1609492c06873?d=identicon&s=25 dave (Guest)
on 2005-11-23 20:48
(Received via mailing list)
On Nov 15, 2005, at 4:11 PM, Edward Frederick wrote:

> Is this simply to illustrate callbacks? Would it not be easier to
> create a virtual accessor:

Basically, yes...
This topic is locked and can not be replied to.