We're looking at the protector gem for attribute level security. I'd like to auto restrict all models to the current user by default so you have to explicitly unrestrict it instead of the other way around. So..
Article.find(3) # Is actually eq to Article.restrict!(current_user).find(3)
But finding it a little challenging to implement it without wrapping/proxying the model. Was wondering if anyone has done this or has an idea of how to implement that type of functionality.
From the protector documentation:
Protector is aware of associations. All the associations retrieved
from restricted instance will automatically be restricted to the same
context. Therefore you don't have to do anything special – it will
respect proper scopes out of the box
You need just to restrict the current User itself.
Related
I can't find any definitive answers to this.
I have a user model with devise, and I have added an 'admin' attribute that is a boolean, which defaults to false. Currently I have to go to the console and manually change the attribute to true to give a user this admin status.
My question is, how secure is this? Is there any way for someone to change the status of their own user without accessing the server (Currently my computer)?
Could safety be compromised once I put the site into production? The admin attribute is not a permitted parameter on sign in, sign up or update.
I am asking as I want to add a personal dashboard for myself to view, edit or delete anything I might need to when the site goes into production.
If you use strong params then the risk is only if you allow setting this attribute from any action outside of admin panel.
To be extra safe you can use attr_readonly so you can only set this attribute when object is created.
Considering Devise, safety is the last thing that could go wrong, unless either one of Rails or Devise is broken, which is unlikely.
You have taken sufficient steps like not allowing the admin parameter, which should be enough for pretty much every situation.
Several Rails applications, including GitHub and Shopify have been doing this (possibly without Devise, but that's not a concern) without security issues. I myself use Devise and admin flags and can vouch that it is safe enough.
Any reason you are not using something like RoleModel? It will allow you to expand to other roles in the future in a much more manageable way than adding an attribute to User for each role.
Either way... unless you provide a way for them to update that field, it should be secure. If you want to ensure that there's no way a non-admin could update that field, you could always add something like this to UsersController#update:
params[:user].delete(:admin) unless current_user.admin?
If I want to build a Rails app that has two different types of users, let's say one type is called players and the other one is owners, what is the best and most efficient approach to modeling the app?
Things to take into account:
There should only be one Login, but different Registration forms that Owners/Players can use.
Owners can have access to a control panel but Players cannot.
Owners cannot share any of Players capabilities, but both need to be able to perform Login/Registration.
I am not using Devise, so please do not suggest it.
Different Approaches I've considered:
Using cancancan gem, but it does not really seem to meet my needs in the sense that I am not looking to create a user/admin hierarchical approach but rather a if you're a Player, then you can see these pages and perform these actions but Owners cannot and vice versa. Almost like splitting the app in two. cancancan seems that it would treat Owners as "Players with extra privileges", not different privileges entirely.
Creating separate models with separate login and registration forms, which seems like a disaster waiting to happen. One small mixup between a Players table and the Owners table, especially with the primary keys, and that will be a world of trouble where people could end up logging in to the wrong accounts.
Creating a polymorphic or has_one relation toward an Account model, which so far, seems like the best way to probably go about it. If I created a polymorphic Account model, I can store different types of Players/Owners, but how could I compare login credentials against all types?
I had been trying to find something on this matter regarding how to map this out and was surprised to not find an information on how to do this without using Devise. If anyone has any good links they can point me to that also address this matter (without Devise), please leave them in your answer! Thanks.
I'd suggest one User class with a type attribute that determines whether the user is a Player or an Owner (single table inheritance). This way you keep the registration logic in one place but can customize the forms depending on the user's class.
There must be alternatives to cancancan that help with what you want to do, or you can implement helpers yourself:
def can_access_control_panel?
current_user.is_a?(Owner)
end
You have to have a way to separate one user from another. One way is to add an attribute to the User table so you can call current_user.role and it will return "owner" or return "player".
I have used Pundit gem in the past. It lets you define which controller actions the current user is allowed to access. So as you create resources for your application, you can add a policy that specifies who is allowed to that given resource. This is the repo to the application.
This answer might help you.
So, I've implemented some permissions between my users and the objects the users modify.. and I would like to lessen the coupling between the views/controllers with the models (calling said permissions). To do that, I had an idea: Implementing some of the permission functionality in the before_save / before_create / before_destroy callbacks. But since the permissions are tied to users (current_user.can_do_whatever?), I didn't know what to do.
This idea may even increase coupling, as current_user is specifically controller-level.
The reason why I initially wanted to do this is:
All over my controllers, I'm having to check if a user has the ability to save / create / destroy. So, why not just return false upon save / create / destroy like rails' .save already does, and add an error to the model object and return false, just like rails' validations?
Idk, is this good or bad? is there a better way to do this?
Let the controller check the user's privileges. To have the model handle authorization logic would lead to more coupling (just in different places, and there'd still be coupling to the controller to get the current user). Checking privileges isn't really internal logic to a model.
Simile: Imagine if it was a file's responsibility to check whether you can read/write to it, instead of having the OS (which is the mother of all controllers, really) handle the access.
If you want cleaner controllers you can (for instance) make some generalized before_filters that restrict access to CRUD actions based on the current user.
Flambino gave you the party line :) but let me add my 2 cents.
It is certainly possible to consider access control logic as part of models.
Model validations is a way of checking the manipulating user's rights on crud actions. A downside of this is exactly the fact that access logic usually generalizes across models, therefore we like to abstract them out like in a neat cancan ability file.
You can actually have your cake and eat it by making your manipulation itself a polymorphic association on models. This is how most audit/version control systems are implemented.
https://github.com/collectiveidea/audited
You could extend it and put your access control logic in audit class validations, so it is in one place.
Audited gem also offers a cunning way to pass the current user to the model level by using an observer as around filter on a controller.
https://github.com/collectiveidea/audited/blob/master/lib/audited/sweeper.rb
but there are other methods too https://github.com/bokmann/sentient_user often considered hacky.
Caveats
In either case you will have to guard against situations when models
are manipulated outside the request cycle (in a background routine,
cronjob, console) when current_user is ill-defined.
You usually do not want to treat access violations with validation
errors but use standard http status code responses.
Third, in a web app setting, you usually manipulate objects via forms
and typically you can already controll access to say an update form
in fact usually coupled with the same access rights as update itself
(cancan even have general alias for new/create and edit/update) so if
the latter is handled with validations, this generalized access logic
will be lost. Not to mention that read-access logic is impossible to
handle with model validations.
hope this helps
I would like to use CanCan on top of a Mongoid based Rails 3 application. I would like to introduce general models for user, role and privilege. Essentially the authorization system shall authorize at a per action base. Therefore we want to store action x roles privilege objects.
Now when it comes to the ability DSL we could generate the abilities dynamically as an after_save hook in the proivilege model. But this results in a problem in production mode, cause these runtime changes only affect the server process where the privilege changes were made.
On the other hand one could reevaluate all (the users) abilities as before_filter in every controller. But that slowed down every request.
Just now, we are undecided how to solve this problem. I am thankful for every suggestion.
Regards
Felix
CanCan uses a simple authorization system based on a role column on the User model.
Here are some good links:
Abilities
Role Based Authorization
Why do you need to dynamically set up privileges? Unless you have a compelling reason to do so you are just introducing unnecessary complexity. Just define the roles you need to with the correct abilities (you can do this on a controller/action basis with cancan) and then assign those roles upon creation/update.
An application has users which can have one of three different account types. Let's call them Small, Medium, Large
I'm trying to figure out the best way to set limits depending on the account type. I looked into cancan but it seems to just have basic authentication options like read, manage, etc. whereas I am mostly going to be doing things like:
if user_has_hit_upload_limit?
# display a message
else
# display the upload form
What's the best way to do this? Am I correct in thinking cancan isn't ideal for this?
I started making a model class that sets all the limits and does all the checks, then added methods to ApplicationHelper to call that class, which is in turn called by the views.
Does this seem reasonable or not good? Is there a better way?
CanCan is for authorization based on abilities defined for users. It's probably not what you want for a quota type system like you described. Assuming you kept track of current usage and the user's quota both in the user model you could write a helper like this:
def user_has_hit_upload_limit?
current_user && current_user.upload_count < current_user.upload_limit
end
The hard part is actually tracking the usage and that will depend on what you are trying to do within your application.
You could still use CanCan define an ability that had a block condition but IMHO that's more complexity then it really needed.