-
Notifications
You must be signed in to change notification settings - Fork 330
Security
If you want to deploy ActiveScaffold in production and expose it to possibly untrusted users, you can take advantage of its security layer to protect your data. The security layer works by paying attention to methods that you can define on your models and controllers. With these methods you may restrict access by taking into account any of the following, as appropriate: the ActiveRecord model, the database record, the current/intended action, and the current user. You may also restrict access at various levels of granularity, forbidding access to an entire action, an entire record, or just a column on the record.
Disclaimer: The security layer in ActiveScaffold is new. Please, please, please test your security setup! If your data is critical and you want complete peace of mind, you must test it yourself. Make sure you have been as specific as possible, and that you have tested to make sure your security methods are being used.
Names a method on the controller that should return the current_user object, when available. The default is :current_user
, which fits nicely with acts_as_authenticated, etc.
session[:user_id] ? User.find(
session[:user_id]) : nil
end
end
A boolean value for what a security check should return in the absence of a relevant method. The default is true
, which lets ActiveScaffold work out of the box. If you need to be security conscious in your application, you should consider setting this to false
so that nothing works until you permit it.
You may restrict an entire action (in the ActiveScaffold plugin sense) by defining a method on your controller in the format #{action_name}_authorized?
. All of the actions are set up with before_filters that check these controller methods. The default behavior of each controller method is to query the scaffold’s ActiveRecord model (see Model Methods below).
Example:
class PostController
active_scaffold :posts
- only authenticated users are authorized to create records
def create_authorized?
self.logged_in?
end
end
On your model object you may define methods in any of three formats, depending on your need for granularity. All methods are defined on the instance level (e.g. def authorized_for_update?
, not def self.authorized_for_update?
). The methods accept no arguments.
The formats are:
- #{column_name}_authorized_for_#{crud_action}?
- #{column_name}_authorized?
- authorized_for_#{crud_action}?
Hopefully these methods are for the most part intuitive. Crud_action is one of :create
, :read
, :update
, and :destroy
. Column_name is not necessarily the name of a database field. It’s the name of whatever column ActiveScaffold is working with, which means it may be a virtual column or it may be an association column.
You may combine methods, and ActiveScaffold will use them intelligently. That is, if you define :authorized_for_update?
and :username_authorized_for_update?
methods, ActiveScaffold will check both and decide which result to use. It does this by simply giving immediate priority to any false response.
ActiveScaffold’s permissions system actually makes the current user available to your records via the :current_user
method. This lets you actually pay attention to who’s logged in and what their roles/permissions are. You should still be prepared to handle the current_user.nil? scenario, though. The current_user may not exist for anonymous users, during cron scripts, or if the model is accessed outside of a request/response cycle.
The second tip is that even though the methods are always at the instance level, the current record isn’t always meaningful. To distinguish whether the specific record matters for the security check, use the :existing_record_check?
method.
- anonymous users may never destroy these/this records
return false unless current_user - and logged-in users are usually authorized to destroy records
return true unless existing_record_check? - unless it’s an existing record and a ‘permanent’ flag has been thrown
return (self.permanent == false)
end
We have tried to design these security methods in a way that lets us spin them off into a new plugin at some future date. The reason they are not a separate plugin yet is because they function passively. That is, they only function when ActiveScaffold is polite enough to care! So please be aware: you can still mess up your data with these security methods in place if you bypass ActiveScaffold (with script/console, for example).