Work in Progress for upcoming 0.7.0 release
Lockdown¶
What¶
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 wil not appear.
If you are interested in using Lockdown for another Ruby framework, please let me know.
Please use either memcache or the database session store instead of the default cookie session store. Due to the current implementation of access_right storage, the size limitations for the cookie may become an issue for larger projects.
Installing¶
$ sudo gem install lockdown $ cd <your_project_directory> $ ./script/generate lockdownThis will give you the following output:
stonean@local ~/Sites/test $ ./script/generate lockdown
exists app/views
exists app/controllers
exists app/helpers
create lib/lockdown
create lib/lockdown/session.rb
create lib/lockdown/init.rb
create app/views/users
create app/views/user_groups
create app/views/permissions
create app/controllers/permissions_controller.rb
create app/helpers/permissions_helper.rb
create app/controllers/users_controller.rb
create app/helpers/users_helper.rb
create app/controllers/user_groups_controller.rb
create app/helpers/user_groups_helper.rb
create app/views/users/index.html.erb
create app/views/users/show.html.erb
create app/views/users/edit.html.erb
create app/views/users/new.html.erb
create app/views/user_groups/index.html.erb
create app/views/user_groups/show.html.erb
create app/views/user_groups/edit.html.erb
create app/views/user_groups/new.html.erb
create app/views/permissions/index.html.erb
create app/views/permissions/show.html.erb
create app/views/sessions
create app/controllers/sessions_controller.rb
create app/views/sessions/new.html.erb
exists app/models
create app/models/permission.rb
create app/models/user.rb
create app/models/user_group.rb
create app/models/profile.rb
create db/migrate
create db/migrate/20090104011604_create_profiles.rb
exists db/migrate
create db/migrate/20090104011605_create_users.rb
exists db/migrate
create db/migrate/20090104011606_create_user_groups.rb
exists db/migrate
create db/migrate/20090104011607_create_permissions.rb
exists db/migrate
create db/migrate/20090104011608_create_admin_user.rb
As you can see, this will create a "lockdown" directory in the lib dir add two files: init.rb and session.rb.
Modify init.rb to set configuration options and define the permissions and user groups that apply to your system.
Please keep the following in mind:
- 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.
Please refer to the lockdown generator page for more detail on the generator and the files it creates.
How it works¶
When the Lockdown generator is run, it adds the necessary config.gem line in your environment.rb.
As your application starts and your environment.rb is 'executed' the config.gem 'lockdown' statement will require Lockdown. When Lockdown is required, it will in turn require your lib/lockdown/init.b and start parsing your rules.
require "lockdown"
require File.join(File.dirname(__FILE__), "session")
Lockdown::System.configure do
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Configuration Options
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Options with defaults:
#
# Set timeout to 1 hour:
# options[:session_timeout] = (60 * 60)
#
# Call method when timeout occurs (method must be callable by controller):
# options[:session_timeout_method] = :clear_session_values
#
# Set system to logout if unauthorized access is attempted:
# options[:logout_on_access_violation] = false
#
# Set redirect to path on unauthorized access attempt:
# options[:access_denied_path] = "/"
#
# Set redirect to path on successful login:
# options[:successful_login_path] = "/"
#
# If deploying to a subdirectory, set that here. Defaults to nil
# options[:subdirectory] = "blog"
# * Notice: I'm still working out the details on this one.
# * Do not add leading or trailing slashes
#
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define permissions
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# set_permission(:product_management, all_methods(:products))
#
# :product_management is the name of the permission which is later
# referenced by the set_user_group method
#
# :all_methods(:products) will return an array of all controller actions
# for the products controller
#
# if products is your standard RESTful resource you'll get:
# ["products/index , "products/show",
# "products/new", "products/edit",
# "products/create", "products/update",
# "products/destroy"]
#
# You can pass multiple parameters to concat permissions such as:
#
# set_permission(:security_management,all_methods(:users),
# all_methods(:user_groups),
# all_methods(:permissions) )
#
# In addition to all_methods(:controller) there are:
#
# only_methods(:controller, :only_method_1, :only_method_2)
#
# all_except_methods(:controller, :except_method_1, :except_method_2)
#
# Some other sample permissions:
#
# set_permission(:sessions, all_methods(:sessions))
# set_permission(:my_account, only_methods(:users, :edit, :update, :show))
#
# Define your permissions here:
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Built-in user groups
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# You can assign the above permission to one of the built-in user groups
# by using the following:
#
# To allow public access on the permissions :sessions and :home:
# set_public_access :sessions, :home
#
# Restrict :my_account access to only authenticated users:
# set_protected_access :my_account
#
# Define the built-in user groups here:
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define user groups
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# set_user_group(:catalog_management, :category_management,
# :product_management)
#
# :catalog_management is the name of the user group
# :category_management and :product_management refer to permission names
#
#
# Define your user groups here:
end
As you can see, the first line requires lockdown. This will load the Lockdown system which consists of various parts:
- Controller
- The controller functionality will add before filters to test each request agains 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.
Roadmap to 1.0¶
**this is tentative and the feature order may change
- Completed: 0.5.0: More generators to ease installation into existing projects
- Completed: 0.6.0: RSpec tests and helper methods for your application. Github project: lockdown-rails-app
- Password reset/reminder, Registration page template generators
- OpenId support
- Merb Support
- Model level security
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) 2008 Andrew Stone