Preventing users from making themselves admins - ruby-on-rails

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"

Related

Allow only one user to be an admin with devise

I`m creating a webpage with rails 6 , devise and cancan .
I need an admin role but i do not want to create a separate model instead i added a Boolean column to user is table , but here`s the thing ,
If any user sign up then it would be a security concern that any user would grant admin privileges only by changing the value of this column to true .
So i thought perhaps i would remove "admin" from "user_params" but then i would have to make this change from the console which is not good enough.
How i should only grant admin to specific user , my thoughts where i would only allow it for the first user only, or specific email but it feels stupid , there must be a smarter way.
How i get the application to have only one admin who can make any other user admin but only him who can do that and if any normal user signed up , no matter what he ca not manipulate this column in any way?
Best Regards
Remove admin from user_params in signup controller. You don't want users to become admin just by preparing request.
Introduce third column super_admin, and grant this role from the console if you have to do it only once.
Create views and controllers only accessible to super_admin where she can update admin for all users.

Devise: instead of creating a new user when signing up, convert an existing guest user into a registered one?

When a guest comes to my website, he is automatically logged in as a User.create guest: true. This way he can easily write comments, etc., and doesn't have to decide to sign up at the very beginning.
If he likes to, he should be able then to sign up later. And here's my question: instead of signing up as a new user, I'd like to convert the existing guest user into a registered user.
Is there an easy way to tell devise to use an existing user? Another way would be to move all the created comments, etc. to the newly created user, but this seems a bit tedious. Or I could remove the guest user and change the newly created user's ID to the deleted one's. In both cases I have to be very careful about dependent: :destroy relations, so it seems rather a bad solution.
Any idea on how to convert the existing user is highly appreciated.
Assuming this is what you mean by guest user then that's just a regular User missing a few fields and with no validations run on it.
When creating a User from an existing guest user just:
def edit
#user = User.find(params[:id])
end
def update
user = User.find(params[:id])
user.update_attributes(params[:user])
end
edit.
You're literally just dealing with a CRUDy user update action. Have your Sign Up anchor tag direct to the edit page for that specific guest_user ala: <%=link_to "Sign Up", edit_user_path(guest_user)%>
I've updated the code example. Assuming you're using a scaffoldish setup, those methods should be in users_controller. You'll want some checks to make sure you handle missing params or errors.
I think you are tricking yourself into thinking you are dealing with a super special case. Guest User is just a User missing some information. Registration just means adding that information to the existing User instance.

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

How would one implement this sort of gradual engagement/lazy registration in Rails?

A long time ago I ran into a website (I unfortunately lost the address, it was some kind of newspaper site) that allowed you to make use of everything as if you were a registered user. You could rate, favorite and comment articles, and when you did it would display a discreet, embedded message saying you had to register to the website for your contributions to be saved. Then it had the link for you to see how your profile would look like if you did, and I was surprised to see it had all my activity there; the articles I read and saved, comments, etc. I left the site and when I came back to it later just out of curiosity, it still had my activity saved.
I thought it was the greatest thing ever, and now that I am in the process of building a website with social features, I would like to take that approach as well. But I am still pretty much a noob and so I don't have much clue as to how to go about it. How would you do it?
I would create a Profile model which is automatically created for any user that visits your site and adds the first favourite, rates the first item, etc. The Profile should be saved to your database including a suitably random and unique string. This string can be stored as a cookie on the client side, and will be used later to retrieve your profile. It should be random and long enough so that you cannot easily tamper with your cookie and get other anonymous people's profiles, but this is not entirely avoidable (so beware you store no sensitive data in anonymous profiles!).
Once a user registers, you can associate their Profile with their new User record and remove the cookie and the unique string identifier. You can now simply retrieve their profiles when they log in, based on their User record.
The Profile model can contain any information you would like to store.
If you want to differentiate between registered users and anonymous users, you could create an AnonymousProfile model and a Profile model (each with different attributes), and simply copy over all data from the anonymous profile to the user profile when someone registers.
Update:
Throughout your application you can decide to only use this information when a user is logged in. You might define a before_filter that grabs the current user, and only if there is an actual user logged in, do you use the profile data:
class ApplicationController < ActionController::Base
before_filter :fetch_user_data
def fetch_user_data
#current_user = ... # Work your magic to get current user
end
private
def current_profile
#current_user and #current_user.profile # Use profile association
end
end
Somewhere in a controller action:
if current_profile
# Do stuff with current_profile
# Only available to registered users...
end
You can later change the implementation of current_profile if you change your mind and want anonymous profiles to have effect for your anonymous users.
The only way to identify users is to use cookies. What the site you were using is likely doing is:
For a first time user create an entry in the 'users' table and add them to the 'guests' group. Save down an identifier cookie to the users machine so you can look them up again later.
If the user decides to register you can fill out the rest of their details in the user table (you might even want to have a separate table for user details and registration details like username/password etc...) and add them to the registered users group.
The way you manage your groups can be as simple as a flag in the database.
As this is a rails question...
I would probably handle most of this in a before_filter in your application_controller.rb. The steps would be something like:
if has_cookie
#user = lookup_user
else
#user = create_new_guest_user
end
You could very easily extend one of the existing authentication frameworks like acts_as_authenticated or clearance to do this.

Resources