views:

562

answers:

6

I'm writing a very simple mailing system for a Rails app. I'm using RESTful authentication. It's a fairly conventional setup, where I'm sending the same email when a user signs up and when a user forgets their password. I'm just having one problem that I can't seem to wrap my head around.

I'd like to use the same email template for both instances, even though the "new user" email will come from a users controller and the "forgot password" email will come from a passwords controller.

The email looks something like this:

<%=h @user.name %>, 
Your membership details:
Username: <%=h @user.login %>
Password: <%=h @user.password %>

When a user signs up, this works just fine, causing an email that looks something like:

  Bryan,
  Your membership details:
  Username: bryan
  Password: password

Unfortunately, everything breaks when attempting to use this template to send a "forgot password" email from the passwords controller. The thing that's perplexing me, though, is that it only sort of breaks:

  Bryan,
  Your membership details:
  Username: bryan
  Password:

In other words, @user.name is still valid, as is @user.login. But for some reason in this state @user.password doesn't come through.

Thanks for the responses. To be clear, security really isn't an issue in this case, and for that reason it'd be nicer to be able to send a forgotten password in plain text rather than going through the resetting password process, but I do appreciate that this is usually not the case.

A: 

I'm guessing that the password is stored in a hashed form, deliberately so that you can't know the user's password. What you need to do when a user forgets a password is to send the user a link, only valid for a few days, that will let the user reset the password without knowing the old one.

Glomek
+2  A: 

It's hard to say without seeing some of your code, specifically the controller methods.

It's possible though that the signup email is using the password before it's encrypted. The unencrypted password generally isn't available to later actions, because it's stored encrypted in the db.

If however your password controller is setting a new password, rather than trying to retrieve the old one, then the problem is most likely elsewhere.

Anyways, that's about as much speculation as one can do without seeing code.

Sarah Mei
+1  A: 

If you look in the database you will see a password hash and a salt hash.

You would have to store the plaintext password in another variable before storing it into the database, using the separate variable with the plaintext password you can pass that to the ActiveMailer and send it without the encryption in the email.

@user = User.find(params[:id])
password = params[:user][:password]
options = {
    :password => password,
    :user => @user
}

if @user.update_attributes(params[:user]) and Mailer.deliver_reset(options)
    flash[:notice] = "Check your email (#{@user.email}) for your new password."
    redirect_to_back_or_default('/')
else
    flash[:error] = "Look at the errors below"
end
Garrett
+1  A: 

I agree with Sarah Mei. It's due to restful auth's way that it stores passwords. Generally attr_accessor :password in the user model sets up a virtual attribute for the password which is then used when you go to sign up. During the signup phase the user object will have the password attribute set to something but when you go to retrieve the user record later on the password field will be blank.

I don't think that's the "best" way of doing things anyway, send them a link where they can reset their password rather than just their original password because if they forgot it once, what's stopping them from forgetting it again?

Ryan Bigg
Yep. This attr_accessor :password has confused me in the past. I'd bet that that's the problem here.
berlin.ab
+1  A: 

Don't do this

Many users use the same passwords in multiple places (yeah, the shouldn't, but they do). Storing their passwords in plain text risks not only the security of your site, but also the security of your users on other sites. And don't even get me started on sending passwords in clear text via e-mail.

Do as the other's here are suggesting, have a password reset system, not a "here's your password" system.

MarkusQ
+1 because passwords in plaintext, or using a reversible 'hash', are one of the biggest security flaws. Period.
Don Werve
Security really isn't an issue with this application, but I would usually agree.
Bryan Woods
@Brian Woods -- If security isn't an issue, don't ask users to give a password. If it is an issue, treat it with respect. Saying "security isn't an issue but we're going to ask users to give a password knowing full well many of them will give one they've used elsewhere" is just irresponsible.
MarkusQ
@MarkusQ That's shortsighted. What if it's an application used internally and informally between myself and a few friends? Session storage and passwords is more about etiquette than security in this case, and building a "reset password" system seems like overkill.
Bryan Woods
@Brian Woods -- You have a strange definition of "shortsighted"; normally that term is used for the sort of reasoning you are using (assuming that because something is limited in scope now it always will be). It also doesn't address the real concern; are you trying to grab your friends's passwords?
MarkusQ
A: 

restful-authentication stores the password only temporarily - just long enough to encrypt it and save the encrypted version. That's for security as others have mentioned.

Since you're not too worried about security for this app, I'd recommend generating a unique token for each user and supplying them with a URL to use for login. Recommending a URL because 'password' (even generated) might give the user the expectation that they can change it. You could email your users something like:

 Bryan,
  Your membership details:
  Username: bryan
  Your url: http://domain.com/x7sjs0qn

Your users could hit that URL and login automatically. That way you never give the user a chance to give you a password they might use elsewhere, and - if they forget it, you can email it in plain text and not put their other accounts at any risk.

dbarker