Lockdown (Vote for Lockdown on RubyTrends)¶
Upgrading notes: Lockdown
Installing¶
For those who want to get right to it, please refer to the lockdown generator page for more detail on the generator.
Note: Once installed, Lockdown prevents access to everything. You must create rules in lib/lockdown/init.rb to open up access.
Things that aren't so obvious and trip people up at the beginning:¶
- When changing your public access rules you must either hit the logout action to reset your session or clear your site's cookie (if you are using the default cookie session store - which I don't recommend) for the new rules to be applied.
- In order to deny/allow access the method has to be defined on the controller. For example, Rails will let you get by without defining an index method if there is an index.html.erb to match the request. You must define the index method on the controller when using Lockdown.
Methods Lockdown provides¶
View Helpers
- links( link_to('A',some_a_url), link_to('B',some_b_url), link_to('C',some_c_url))
Will join links with a pipe (option to change this character in init.rb). If the user doesn't have access, the link won't appear. example: in the above, if user didn't have access to 'B', you would get: <a href="some_a_url">A</a> | <a href="some_c_url">C</a>
- link_to_or_show(*args, &block)
Works just the same as link_to, but if the user doesn't have access it will output the name without the link.
Session methods
- reset_lockdown_session
Nilifies these session values: [:expiry_time, :current_user_id, :access_rights]
- current_user_access_in_group?(:group_symbol)
Returns true or false if user has access to ANY permission in the group. It does NOT require that the user has access to ALL permissions associated to the group.
- current_user_is_admin?
Simple enough.
System methods
- Lockdown::System.public_access
Returns the array of public rights ("#{controller}/#{action}").
- Lockdown::System.access_rights_for_user(user)
Returns the array of rights ("#{controller}/#{action}") the user has access to.
- Lockdown::System.user_groups_assignable_for_user(user)
Pass in a user object to this method and you'll get back an array of UserGroup objects the user would be allowed to assign to someone else. This can be used to prevent a user from assigning more power than he/she has. Example in users_controller template.
- Lockdown::System.permissions_assignable_for_user(user)
Pass in a user object to this method and you'll get back an array of Permission objects the user would be allowed to assign to someone else. This can be used to prevent a user from assigning more power than he/she has. Example in user_groups_controller template.
- Lockdown::System.permissions_for_user_group(user_group)
Pass in a user group object and you'll get back an array of permission names (as symbols).
- Lockdown::System.access_rights_for_permission(permission_symbol)
Pass in a permission symbol and you'll get back the array of rights ("#{controller}/#{action}") for the permission.
- Lockdown::System.get_user_groups
Returns an array of user group names (as symbols) defined in init.rb.
- Lockdown::System.get_permissions
Returns an array of permission names (as symbols) defined in init.rb.
Options Lockdown provides¶
These options are set in RAILS_ROOT/lib/lockdown/init.rb
- session_timeout
defaults: one hour
- session_timeout_method
method to call when session times out. defaults:clear_session_values
- logout_on_access_violation
log the user out if they try to access a restricted resource. default: false
- access_denied_path
set redirect_to path on an unauthorized access attempt. default: '/'
- successful_login_path
set redirect_to after successful login. default: '/'
- links_separator
set separator used in links method. default: '|'
- subdirectory
will prepend subdirectory to paths. requested feature for some setups
About¶
Lockdown is a authentication/authorization system for RubyOnRails (ver 2.x). Here's a quick summary of Lockdown:
- Permissions are the root of the system. A permission consists of a collection of controller actions, e.g. "users/new", "users/edit", etc...
A permission can consist of any combination of controllers and actions, more about this later.
- Instead of roles, Lockdown uses UserGroups to associate permissions to a user. A user can belong to multiple UserGroups.
A UserGroup consists of a collection of permissions.
- Lockdown utilizes a centralized file
lib/lockdown/init.rbto declare your access rights, e.g. permissions and user groups.
This allows you manage the security of your application in one place. No before_filters scattered in your controllers.
- Lockdown intercepts (aliases) the link_to and button_to helper calls. If the user does not have access, the link/button will not appear.
If you are interested in using Lockdown for another Ruby framework, please let me know.
NOTE:
Due to the current implementation of access_right storage, the size limitations for the cookie may become an issue for larger projects. Please use either memcache or the database session store instead of the default cookie session store.
Upgrading to 0.9.0¶
Things have changed quite a bit. Lockdown should no longer be considered an authentication system. It never really was, it just provided some generators that do authentication. Those generators still exist but are deprecated an will not be maintained. If you want to use them:./script/generate lockdown --add-lockdown-authentication --add-management --add-loginRAILS_ROOT/lib/lockdown/session has been removed and a new README has been added to explain what is required for Lockdown to work with another authentication system. It's pretty simple actually:
# # !!!!IMPORTANT!!!! # #*** MUST define a current_user method that will return the current user object # #*** MUST add call to add_lockdown_session_values to your login method # #*** MAY NEED to add call to reset_lockdown_session to your logout method. # ** Not needed if your authentication system resets the session # # Definitely need to use the user_group and permission models. The lockdown # generator will provide those for you. Just add the following to your user # model: # has_and_belongs_to_many :user_groups # # That's it! # # # ~~~~Method Descriptions~~~~ # The Lockdown gem defines these session methods: # # current_user_id: returns the id of the current_user # # logged_in? : returns true if current_user_id > 0 # # current_user_is_admin?: returns true if user is assigned # administrator rights. # # reset_lockdown_session: This will nil the following session values: # current_user_id # access_rights # expiry_time # # current_user_access_in_group?(grp): grp is a symbol referencing a # Lockdown::UserGroups method such as :registered_users # Will return true if the session[:access_rights] contain at # least one match to the access_right list associated to the group # # If you want access to any of these methods in your view, just add them # as helpers in your controller (application controller for global use). #
Upgrading to 0.8.0¶
If you are running an old, old version of Lockdown, you'll want do do the upgrading to 0.7.0 steps as well!
Okay, I didn't want to have to do this, but the implementation of System.configure had to be changed to support future functionality. What does that mean? Well, the way you define your permissions has changed to be more DSL-ly. I needed to do this for future model level functionality (don't worry, it's worth it!). If you're decent at search/replace it should pretty painless.
Please refer to the lockdown generator page for the new syntax. Here's some examples:
What was:
set_permission :users_management, all_methods(:users)
Is now:
set_permission(:users_management).
with_controller(:users)
What was:
set_permission :my_account, only_methods(:users, :edit, :update, :show)
Is now:
set_permission(:my_account).
with_controller(:users).
only_methods(:edit, :update, :show)
Upgrading to 0.7.0¶
There are just a few of things you need to do in your app to play nice with this upgrade:
- Remove your require 'lockdown/init' or config.gem 'lockdown' statements from your config/environment.rb.
- Remove the require 'lockdown' statement from you lib/lockdown/init.rb. The gem now handles this for you.
- Create a new file in your config/initializers directory called lockit.rb. Add just one line: require 'lockdown'
The load order is the reasoning behind initializing lockdown this way, especially if you are using the resource_controller plugin.
How it works¶
Some points to notice:
- All Permissions are defined in init.rb, they cannot be defined via the administration screens.
- All User Groups should be defined in init.rb. The administration screens can be used to create user groups, but doing so should be reserved for the unexpected.
Why? Simply because creating User Groups via the administration screens will only add more work for you if you want to run tests using those groups.
- Lockdown will sync up the rules (Permissions and User Groups) defined in init.rb with your database. You can turn off this feature.
- Controller
- The controller functionality will add before filters to test each request against the defined access_rights for the current user. If the current request is not in the access_rights list, access right is denied.
- Model
- The model functionality will automatically set the updated_by/created_by fields of your model to the current_profile_id.
- View
- The view functionality intercepts the link_to method (aliases it). If the current user does not have rights to the link, the link will not show.<br/>There is also a link_to_or_show method (same params as link_to) that will print out just the name of the link (no anchor tag) if the current user does not have access.
When referring to access rights: if you have a standard REST users controller, the access rights would be:
users/index users/show users/edit users/update users/new users/create users/destroy
The internals¶
All configuration of Lockdown (Permissions and User Groups) are done in lib/lockdown/init.rb. The database functionality is merely an extension of the definitions to allow for the dynamic creation of User Groups. Permissions can not be created via the administration screens.
Lockdown doesn't have a concept of Roles. Instead, Lockdown users can be associated to one or many User Groups to allow for flexibility. In addition, you can use the admin screens to add new User Groups to the database. User groups are nothing more than a grouping mechanism for Permissions to ease management.
Here are the parts to Lockdown:
- Profiles
- The profile model contains all non-user information related to person. Lockdown uses the profile record as the reference for updated_by and created_by. This allows you to remove the user record completely when you want to revoke access, but you still retain the foreign key for history.<br/>Here are the fields you have to start with:</p>
- first_name : string
- last_name : string
- email : string
- The profile model contains all non-user information related to person. Lockdown uses the profile record as the reference for updated_by and created_by. This allows you to remove the user record completely when you want to revoke access, but you still retain the foreign key for history.<br/>Here are the fields you have to start with:</p>
- Users
- The user model contains all user information related to person.<br/>Here are the fields you have to start with:
- login : string
- crypted_password : string
- salt : string
- profile_id : integer
- The user model contains all user information related to person.<br/>Here are the fields you have to start with:
- User Groups
- User Groups exist only to group Permissions. All functionality for your site should be covered by the user groups you define in init.rb. You can use the admin screen to create new user groups if the need arises. The database model only has one field:
- name : string
- User Groups exist only to group Permissions. All functionality for your site should be covered by the user groups you define in init.rb. You can use the admin screen to create new user groups if the need arises. The database model only has one field:
- Permissions
- Permissions are the security building blocks of your system and are defined in init.rb. A permission maps to controller(s)/action(s) in your system. Please refer back to the documentation in init.rb on how to create permissions.
As permissions relate to system functionality, they cannot be created via the admin screen. The database model only has one field:- name : string
- Permissions are the security building blocks of your system and are defined in init.rb. A permission maps to controller(s)/action(s) in your system. Please refer back to the documentation in init.rb on how to create permissions.
Github¶
http://github.com/stonean/lockdown/tree/master
clone url: git://github.com/stonean/lockdown.git
Contact¶
Please use the forum to ask questions and the issue tracker to report problems or submit a pull request.
License¶
This code is free to use under the terms of the MIT license.
Copyright (c) 2009 Andrew Stone