Conditional password validation in Rails - ruby-on-rails

In my application I have two ways of singing up users:
Sign up form
Facebook Connect
In both ways we store information into the database, but just in the first want we want to store the password.
I have some password related validations that I want to be performed for the first way of users signing up, but I don't want it to happen for the second one. What would be the appropriate and secure way of doing this in Rails?
My first approach was creating an attribute for the user object called password_optional and do a conditional in the validation with that, but I'm not sure how can I set that attribute by default to false or set it to false when the user is signing up using the form.

If you don't have a password when user signs up via facebook, but your validation requires it, set it to some random string then.
This is exactly what is recommended in Devise documentation.

Skip the validations when you don't need it. There are multiple ways of doing that
Maybe you could have two models User::Normal < User and User::Facebook < User. Most of the logic goes into User, and specificities go into the custom models.
Maybe you could just go validates_presence_of :password, :if => not_facebook? or something of the sort.

Related

Best way to send registration email (DEVISE)

Devise allows you to customize mailers here.
https://github.com/plataformatec/devise/wiki/How-To:-Use-custom-mailer.
However, I can also make a my own actionmailer like here.
http://railscasts.com/episodes/206-action-mailer-in-rails-3
When a user registers on my site, I would like to send two different emails, one to myself with the registration information and one to the user to thank them for registering.
What is the best way to do this? or is there a method that devise has that would allow me to do this? I was thinking of creating a hook(call back) in the model after a user is created. However, that would mean if I manually create a record, the registration emails would also be sent out. I don't want an email to be sent out if I manually create a user. Any advice?
You could have a callback such as after_create :send_email_to_admin
def send_email_to_admin
# your implementation
end
You would also put a conditional so it doesn't send an email when it's yourself creating the record manually. I do not think Devise offers such an option.
3 workarounds if you don't want to send email to your manually created users.
Create users at first, then add the hook.
Add a special pattern on the email of your manually created users. Say (.*)-very-weird-suffix#weired-email.com. You judge this pattern in the hook.
Add a field in users table to check if the account is created by you. I really don't recommend this unless creating accounts is part of your daily job.

Rails - Malicious user overriding user name

Imagine you have a user model with a user name and several other attributes. A user will only be able to set a username while singing up, not later when editing his profile.
Still, the :user_name attribute needs to accessible through attr_accessible in the user model for the registration form.
This makes me wonder whether a malicious user could change the form that allows him to edit his profile, and change an input name to user_name and thereby in fact change it upon submit.
Am I right about this, i.e. could a malicious user do that or will Ruby find out somehow that the form was altered? If this is a security issue, how can I always reset the user name in my update method? Is there a rails way of differentiating between accessible and accessible but non-editable attributes?
No, it's not possible due to Rails' CSRF counter measures. See this guide.
You should have the following line in your application controller:
protect_from_forgery :secret => "123456789012345678901234567890..."
Also have a look at the following article for further information on XSS, which describes in some detail what is possible and counter-measures to take.
Always sanitize() input.

Rails: how to skip validation routine on register and run it on login?

I'm trying to build the backend for a subscription-only area for a website.
When the customer first pays for the subscription, he is going to be registered automatically by a callback from an external app confirming the user has paid.
I want to create the user automatically with several blank attributes. Once the user tries to login for the first time, he has to change or update all of these attributes. Then I want to run the validation routine for the attributes.
Assume the user knows his username and first password as he completes the payment.
The authentication is currently being done with Devise, but it is subject to change.
How would you go about implementing this on Rails?
You could use :on => :update after the relevant validations to bypass them on registration. Then, create a before_filter that redirects logged in users to their profile edit page throughout your application if at least one required attribute is missing.
You can just .save(false) on creation to prevent the validation completely
Not as good of a solution for your problem, but for others like me who got here through Google...
http://guides.rubyonrails.org/v2.3.11/activerecord_validations_callbacks.html#skipping-validations

Email confirmation in Rails without using any existing authentication gems/plugins

I'm working on this alerting service in Rails. And really, all I need to do is, when a user signs up, send a confirmation email to the user. And upon confirmation from the user, activate the user. I tried playing around with Matt Hooks' Authlogic email activation tutorial, but its really leading nowhere. So , any ideas how I can do this with minimum fuss ?
Thanks !
UPDATE
So how i got devise to do the job for me is :
Install the gem.
Create a migration for devise's confirmable fields.
Specify
devise :confirmable
in your model.
Create a confirm method in the relevant controller(and a route for that method) which would update the confirmed_at attribute of the relevant model.
The devise generator creates a few views for you, one which is confirmation_instructions.html.erb. Customize the path there.
I used Rails 2.3.2 and I 've used this method along with Authlogic's authentication and it worked well. I do plan to switch to devise completely.
In all honesty, I wanted to accept both answers (unfortunately I can't do that), but its just that the devise solution seemed a easier solution.
Assuming given the title that you definitely want to avoid Devise, Authlogic and friends, here's what I think you need to do:
Create 'confirmation code' and 'confirmed' attributes in your user model.
Create a new controller method on your user controller that expects a user id and confirmation code, looks up the user and then checks if the code in the parameter matches the code stored in the DB. If so, it clears the code and sets confirmed = true.
Create a route that maps e.g. /users/1/confirm/code to your new controller method.
Create an ActionMailer template for the e-mail you want to send. This should accept a user as a parameter, and use the confirmation code of the user to send a mail containing a link to your new route.
Create an observer for your user model. If the record is created or the e-mail address modified, then generate a random confirmation code, set it into the model and clear the confirmed flag. Then trigger your ActionMailer.
Create a helper method which allows views to check if the current user is confirmed.
Use this method to enable/disable functionality as appropriate. Remember to protect your controller methods as appropriate as well as your view logic.
You could also make use of scopes for selecting users.
class User < ActiveRecord::Base
scope :certified, where(:certified => true)
end
And then in your code:
#user = User.certified.find_by_username(foo)
Devise is an other excellent authentication gem that comes with email activation build in, perhaps you could give it a go.

Preventing users from making themselves admins

In my app, I have a "User" model, which includes a number of attributes including "has_admin_rights". If true, the user is an admin, if false, they aren't.
Each user has a profile, with their login name, email address, profile pic, etc.
If I'm logged in as a regular user, I can click on a page called "profile", and I can edit my own account, e.g. updating my email address, profile pic, password, whatever. I can ONLY edit my account, and no other.
If I'm logged in as an admin, I can do a little more: for example, I can make ANOTHER user an admin, or take away their admin rights.
Now, only an admin has access to the view where the "make admin" check box appears, but I have a feeling that simply restricting access to the view isn't sufficient.
What I'm concerned about is, since any user can edit their own profile, what's there to stop a user from submitting a custom form post, which has in it the "has_admin_rights"=>"1" parameter on their own account - thereby granting themselves admin access?
What I'm thinking is that, in the User controller, before applying any changes to the "has_admin_rights" field, that I need to check to make sure the user making the request is currently an admin - otherwise I ignore the request altogether, and make no changes.
in the User controller, before applying any changes to the "has_admin_rights" field, that I need to check to make sure the user making the request is currently an admin - otherwise I ignore the request altogether, and make no changes.
yes, exactly. Never trust the client; remember that anybody can just tweak the page directly with Firebug or whatever.
I'd also suggest that you consider adding an audit trail, and log something whenever one admin makes another user into an admin. Maybe also send email to all the admins for a particular group to let them know that an admin has been created (or that rights have been revoked).
attr_protected is pretty useful, too
class User < ActiveRecord::Base
attr_protected :is_admin
end
Add a before_save in your User model that performs this validation .
Ue attr_accessible which white list of model attributes that can be set via mass-assignment
class User < ActiveRecord::Base
attr_accessible :has_admin_rights
end
& in controller
#user.has_admin_rights = current_user.is_admin? "1" : "0"

Resources