andrewzielinski-lockdown 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +195 -0
- data/README.txt +36 -0
- data/Rakefile +41 -0
- data/lib/lockdown.rb +70 -0
- data/lib/lockdown/context.rb +41 -0
- data/lib/lockdown/database.rb +105 -0
- data/lib/lockdown/frameworks/rails.rb +146 -0
- data/lib/lockdown/frameworks/rails/controller.rb +147 -0
- data/lib/lockdown/frameworks/rails/view.rb +61 -0
- data/lib/lockdown/helper.rb +95 -0
- data/lib/lockdown/orms/active_record.rb +68 -0
- data/lib/lockdown/permission.rb +204 -0
- data/lib/lockdown/rules.rb +289 -0
- data/lib/lockdown/session.rb +57 -0
- data/lib/lockdown/system.rb +57 -0
- data/rails_generators/lockdown/lockdown_generator.rb +273 -0
- data/rails_generators/lockdown/templates/app/controllers/permissions_controller.rb +22 -0
- data/rails_generators/lockdown/templates/app/controllers/sessions_controller.rb +39 -0
- data/rails_generators/lockdown/templates/app/controllers/user_groups_controller.rb +122 -0
- data/rails_generators/lockdown/templates/app/controllers/users_controller.rb +117 -0
- data/rails_generators/lockdown/templates/app/helpers/permissions_helper.rb +2 -0
- data/rails_generators/lockdown/templates/app/helpers/user_groups_helper.rb +2 -0
- data/rails_generators/lockdown/templates/app/helpers/users_helper.rb +2 -0
- data/rails_generators/lockdown/templates/app/models/permission.rb +13 -0
- data/rails_generators/lockdown/templates/app/models/profile.rb +10 -0
- data/rails_generators/lockdown/templates/app/models/user.rb +95 -0
- data/rails_generators/lockdown/templates/app/models/user_group.rb +15 -0
- data/rails_generators/lockdown/templates/app/views/permissions/index.html.erb +16 -0
- data/rails_generators/lockdown/templates/app/views/permissions/show.html.erb +26 -0
- data/rails_generators/lockdown/templates/app/views/sessions/new.html.erb +12 -0
- data/rails_generators/lockdown/templates/app/views/user_groups/edit.html.erb +33 -0
- data/rails_generators/lockdown/templates/app/views/user_groups/index.html.erb +20 -0
- data/rails_generators/lockdown/templates/app/views/user_groups/new.html.erb +31 -0
- data/rails_generators/lockdown/templates/app/views/user_groups/show.html.erb +29 -0
- data/rails_generators/lockdown/templates/app/views/users/edit.html.erb +51 -0
- data/rails_generators/lockdown/templates/app/views/users/index.html.erb +22 -0
- data/rails_generators/lockdown/templates/app/views/users/new.html.erb +50 -0
- data/rails_generators/lockdown/templates/app/views/users/show.html.erb +33 -0
- data/rails_generators/lockdown/templates/config/initializers/lockit.rb +1 -0
- data/rails_generators/lockdown/templates/db/migrate/create_admin_user.rb +17 -0
- data/rails_generators/lockdown/templates/db/migrate/create_permissions.rb +19 -0
- data/rails_generators/lockdown/templates/db/migrate/create_profiles.rb +26 -0
- data/rails_generators/lockdown/templates/db/migrate/create_user_groups.rb +19 -0
- data/rails_generators/lockdown/templates/db/migrate/create_users.rb +17 -0
- data/rails_generators/lockdown/templates/lib/lockdown/README +42 -0
- data/rails_generators/lockdown/templates/lib/lockdown/init.rb +122 -0
- data/spec/lockdown/database_spec.rb +158 -0
- data/spec/lockdown/frameworks/rails/controller_spec.rb +224 -0
- data/spec/lockdown/frameworks/rails/view_spec.rb +125 -0
- data/spec/lockdown/frameworks/rails_spec.rb +175 -0
- data/spec/lockdown/permission_spec.rb +156 -0
- data/spec/lockdown/rules_spec.rb +109 -0
- data/spec/lockdown/session_spec.rb +89 -0
- data/spec/lockdown/system_spec.rb +59 -0
- data/spec/lockdown_spec.rb +19 -0
- data/spec/rcov.opts +5 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +1 -0
- metadata +112 -0
@@ -0,0 +1,122 @@
|
|
1
|
+
class <%= "#{namespace.camelcase}::" unless namespace.blank? %>UserGroupsController < ApplicationController
|
2
|
+
before_filter :find_user_group, :only => [:show, :edit, :update, :destroy]
|
3
|
+
after_filter :update_permissions, :only => [:create, :update]
|
4
|
+
|
5
|
+
# GET /user_groups
|
6
|
+
# GET /user_groups.xml
|
7
|
+
def index
|
8
|
+
@user_groups = UserGroup.find(:all)
|
9
|
+
|
10
|
+
respond_to do |format|
|
11
|
+
format.html # index.html.erb
|
12
|
+
format.xml { render :xml => @user_groups }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# GET /user_groups/1
|
17
|
+
# GET /user_groups/1.xml
|
18
|
+
def show
|
19
|
+
@all_permissions = Lockdown::System.permissions_assignable_for_user(current_user)
|
20
|
+
respond_to do |format|
|
21
|
+
format.html # show.html.erb
|
22
|
+
format.xml { render :xml => @user_group }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# GET /user_groups/new
|
27
|
+
# GET /user_groups/new.xml
|
28
|
+
def new
|
29
|
+
@user_group = UserGroup.new
|
30
|
+
@all_permissions = Lockdown::System.permissions_assignable_for_user(current_user)
|
31
|
+
|
32
|
+
respond_to do |format|
|
33
|
+
format.html # new.html.erb
|
34
|
+
format.xml { render :xml => @user_group }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# GET /user_groups/1/edit
|
39
|
+
def edit
|
40
|
+
@all_permissions = Lockdown::System.permissions_assignable_for_user(current_user)
|
41
|
+
end
|
42
|
+
|
43
|
+
# POST /user_groups
|
44
|
+
# POST /user_groups.xml
|
45
|
+
def create
|
46
|
+
@user_group = UserGroup.new(params[:user_group])
|
47
|
+
|
48
|
+
respond_to do |format|
|
49
|
+
if @user_group.save
|
50
|
+
flash[:notice] = 'UserGroup was successfully created.'
|
51
|
+
<% if namespace %>
|
52
|
+
format.html { redirect_to(<%= namespace %>_user_group_path(@user_group)) }
|
53
|
+
<% else %>
|
54
|
+
format.html { redirect_to(user_group_path(@user_group)) }
|
55
|
+
<% end %>
|
56
|
+
format.xml { render :xml => @user_group, :status => :created, :location => @user_group }
|
57
|
+
else
|
58
|
+
@all_permissions = Lockdown::System.permissions_assignable_for_user(current_user)
|
59
|
+
format.html { render :action => "new" }
|
60
|
+
format.xml { render :xml => @user_group.errors, :status => :unprocessable_entity }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# PUT /user_groups/1
|
66
|
+
# PUT /user_groups/1.xml
|
67
|
+
def update
|
68
|
+
respond_to do |format|
|
69
|
+
if @user_group.update_attributes(params[:user_group])
|
70
|
+
flash[:notice] = 'UserGroup was successfully updated.'
|
71
|
+
<% if namespace %>
|
72
|
+
format.html { redirect_to(<%= namespace %>_user_group_path(@user_group)) }
|
73
|
+
<% else %>
|
74
|
+
format.html { redirect_to(user_group_path(@user_group)) }
|
75
|
+
<% end %>
|
76
|
+
format.xml { head :ok }
|
77
|
+
else
|
78
|
+
@all_permissions = Lockdown::System.permissions_assignable_for_user(current_user)
|
79
|
+
format.html { render :action => "edit" }
|
80
|
+
format.xml { render :xml => @user_group.errors, :status => :unprocessable_entity }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# DELETE /user_groups/1
|
86
|
+
# DELETE /user_groups/1.xml
|
87
|
+
def destroy
|
88
|
+
@user_group.destroy
|
89
|
+
|
90
|
+
respond_to do |format|
|
91
|
+
format.html { redirect_to(<%= namespace.blank? ? 'user_groups_path' : "#{namespace}_user_groups_path" %>) }
|
92
|
+
format.xml { head :ok }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def find_user_group
|
99
|
+
@user_group = UserGroup.find(params[:id])
|
100
|
+
if <%= action_name %> != "show" && Lockdown::System.has_user_group?(@user_group)
|
101
|
+
raise SecurityError,"Invalid attempt to modify user group."
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def update_permissions
|
106
|
+
new_perm_ids = params.collect{|p| p[0].split("_")[1].to_i if p[0] =~ /^perm_/}.compact
|
107
|
+
#
|
108
|
+
# Removed previously associated permissions if not checked this time.
|
109
|
+
#
|
110
|
+
@user_group.permissions.dup.each do |p|
|
111
|
+
@user_group.permissions.delete(p) unless new_perm_ids.include?(p.id)
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Add in the new permissions
|
116
|
+
#
|
117
|
+
new_perm_ids.each do |id|
|
118
|
+
next if @user_group.permission_ids.include?(id)
|
119
|
+
@user_group.permissions << Permission.find(id)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
class <%= "#{namespace.camelcase}::" unless namespace.blank? %>UsersController < ApplicationController
|
2
|
+
before_filter :find_user, :only => [:show, :edit, :update, :destroy]
|
3
|
+
after_filter :update_user_groups, :only => [:create, :update]
|
4
|
+
# GET /users
|
5
|
+
# GET /users.xml
|
6
|
+
def index
|
7
|
+
@users = User.find :all, :include => [:profile, :user_groups]
|
8
|
+
respond_to do |format|
|
9
|
+
format.html # index.html.erb
|
10
|
+
format.xml { render :xml => @users }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# GET /users/1
|
15
|
+
# GET /users/1.xml
|
16
|
+
def show
|
17
|
+
@user_groups_for_user = Lockdown::System.user_groups_assignable_for_user(current_user)
|
18
|
+
respond_to do |format|
|
19
|
+
format.html # show.html.erb
|
20
|
+
format.xml { render :xml => @user }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# GET /users/new
|
25
|
+
# GET /users/new.xml
|
26
|
+
def new
|
27
|
+
@user = User.new
|
28
|
+
@user_groups_for_user = Lockdown::System.user_groups_assignable_for_user(current_user)
|
29
|
+
respond_to do |format|
|
30
|
+
format.html # new.html.erb
|
31
|
+
format.xml { render :xml => @user }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# GET /users/1/edit
|
36
|
+
def edit
|
37
|
+
@user_groups_for_user = Lockdown::System.user_groups_assignable_for_user(current_user)
|
38
|
+
end
|
39
|
+
|
40
|
+
# POST /users
|
41
|
+
# POST /users.xml
|
42
|
+
def create
|
43
|
+
@user = User.new(params[:user])
|
44
|
+
|
45
|
+
if @user.save
|
46
|
+
flash[:notice] = "Thanks for signing up!"
|
47
|
+
redirect_to(<%= namespace.blank? ? 'user_path(@user)' : "#{namespace}_user_path(@user)" %>)
|
48
|
+
else
|
49
|
+
@user_groups_for_user = Lockdown::System.user_groups_assignable_for_user(current_user)
|
50
|
+
flash[:error] = "Please correct the following issues"
|
51
|
+
render :action => "new"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# PUT /users/1
|
56
|
+
# PUT /users/1.xml
|
57
|
+
def update
|
58
|
+
@user.attributes = params[:user]
|
59
|
+
|
60
|
+
respond_to do |format|
|
61
|
+
if @user.save
|
62
|
+
flash[:notice] = 'User was successfully updated.'
|
63
|
+
format.html { redirect_to(<%= namespace.blank? ? 'user_path(@user)' : "#{namespace}_user_path(@user)"%>) }
|
64
|
+
format.xml { head :ok }
|
65
|
+
else
|
66
|
+
@user_groups_for_user = Lockdown::System.user_groups_assignable_for_user(current_user)
|
67
|
+
format.html { render :action => "edit" }
|
68
|
+
format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# DELETE /users/1
|
74
|
+
# DELETE /users/1.xml
|
75
|
+
def destroy
|
76
|
+
@user.destroy
|
77
|
+
|
78
|
+
respond_to do |format|
|
79
|
+
format.html { redirect_to(<%= namespace.blank? ? 'users_path' : "#{namespace}_users_path" %>) }
|
80
|
+
format.xml { head :ok }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def change_password
|
85
|
+
render :update do |page|
|
86
|
+
page.replace_html 'password', :partial => 'password'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def find_user
|
93
|
+
# Skip test if current user is an administrator
|
94
|
+
unless current_user_is_admin?
|
95
|
+
# Raise error if id not = current logged in user
|
96
|
+
raise SecurityError.new if (current_user_id != params[:id].to_i)
|
97
|
+
end
|
98
|
+
@user = User.find(params[:id])
|
99
|
+
raise SecurityError.new if @user.nil?
|
100
|
+
end
|
101
|
+
|
102
|
+
def update_user_groups
|
103
|
+
new_ug_ids = params.collect{|p| p[0].split("_")[1].to_i if p[0] =~ /^ug_/}.compact
|
104
|
+
# Removed previously associated user_groups if not checked this time.
|
105
|
+
#
|
106
|
+
@user.user_groups.dup.each do |g|
|
107
|
+
@user.user_groups.delete(g) unless new_ug_ids.include?(g.id)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Add in the new permissions
|
111
|
+
#
|
112
|
+
new_ug_ids.each do |id|
|
113
|
+
next if @user.user_group_ids.include?(id)
|
114
|
+
@user.user_groups << UserGroup.find(id)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Permission < ActiveRecord::Base
|
2
|
+
has_and_belongs_to_many :user_groups
|
3
|
+
|
4
|
+
def all_users
|
5
|
+
User.find_by_sql <<-SQL
|
6
|
+
select users.*
|
7
|
+
from users, user_groups_users, permissions_user_groups
|
8
|
+
where users.id = user_groups_users.user_id
|
9
|
+
and user_groups_users.user_group_id = permissions_user_groups.user_group_id
|
10
|
+
and permissions_user_groups.permission_id = #{self.id}
|
11
|
+
SQL
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class Profile < ActiveRecord::Base
|
2
|
+
SYSTEM = 1
|
3
|
+
|
4
|
+
validates_presence_of :email, :first_name, :last_name
|
5
|
+
|
6
|
+
validates_length_of :email, :within => 5..100
|
7
|
+
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
|
8
|
+
|
9
|
+
validates_uniqueness_of :email, :case_sensitive => false
|
10
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
class User < ActiveRecord::Base
|
3
|
+
has_and_belongs_to_many :user_groups
|
4
|
+
belongs_to :profile
|
5
|
+
|
6
|
+
# Virtual attributes
|
7
|
+
attr_accessor :password
|
8
|
+
|
9
|
+
validates_presence_of :login
|
10
|
+
validates_presence_of :password, :if => :password_required?
|
11
|
+
validates_presence_of :password_confirmation, :if => :password_required?
|
12
|
+
validates_length_of :password, :within => 4..40, :if => :password_required?
|
13
|
+
validates_confirmation_of :password, :if => :password_required?
|
14
|
+
validates_length_of :login, :within => 3..40
|
15
|
+
validates_uniqueness_of :login, :case_sensitive => false
|
16
|
+
|
17
|
+
before_save :encrypt_password
|
18
|
+
before_save :save_profile
|
19
|
+
|
20
|
+
attr_accessible :login, :password, :password_confirmation,
|
21
|
+
:first_name, :last_name, :email
|
22
|
+
|
23
|
+
# Authenticates a user by their login name and unencrypted password.
|
24
|
+
# Returns the user or nil.
|
25
|
+
def self.authenticate(login, password)
|
26
|
+
u = find :first, :conditions => ['login = ?', login] # need to get the salt
|
27
|
+
u && u.authenticated?(password) ? u : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# Encrypts some data with the salt.
|
31
|
+
def self.encrypt(password, salt)
|
32
|
+
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
33
|
+
end
|
34
|
+
|
35
|
+
# Encrypts the password with the user salt
|
36
|
+
def encrypt(password)
|
37
|
+
self.class.encrypt(password, salt)
|
38
|
+
end
|
39
|
+
|
40
|
+
def authenticated?(password)
|
41
|
+
crypted_password == encrypt(password)
|
42
|
+
end
|
43
|
+
|
44
|
+
def full_name
|
45
|
+
first_name + " " + last_name
|
46
|
+
end
|
47
|
+
|
48
|
+
# Profile information
|
49
|
+
def first_name
|
50
|
+
user_profile.first_name
|
51
|
+
end
|
52
|
+
|
53
|
+
def first_name=(string)
|
54
|
+
user_profile.first_name = string
|
55
|
+
end
|
56
|
+
|
57
|
+
def last_name
|
58
|
+
user_profile.last_name
|
59
|
+
end
|
60
|
+
|
61
|
+
def last_name=(string)
|
62
|
+
user_profile.last_name = string
|
63
|
+
end
|
64
|
+
|
65
|
+
def email
|
66
|
+
user_profile.email
|
67
|
+
end
|
68
|
+
|
69
|
+
def email=(string)
|
70
|
+
user_profile.email = string
|
71
|
+
end
|
72
|
+
|
73
|
+
def user_profile
|
74
|
+
self.profile || self.profile = Profile.new
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
def encrypt_password
|
80
|
+
return if password.blank?
|
81
|
+
if new_record?
|
82
|
+
self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--")
|
83
|
+
end
|
84
|
+
self.crypted_password = encrypt(password)
|
85
|
+
end
|
86
|
+
|
87
|
+
def save_profile
|
88
|
+
profile.save
|
89
|
+
end
|
90
|
+
|
91
|
+
def password_required?
|
92
|
+
(crypted_password.blank? || !password.blank?)
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class UserGroup < ActiveRecord::Base
|
2
|
+
has_and_belongs_to_many :permissions
|
3
|
+
has_and_belongs_to_many :users
|
4
|
+
|
5
|
+
validates_presence_of :name
|
6
|
+
|
7
|
+
def all_users
|
8
|
+
User.find_by_sql <<-SQL
|
9
|
+
select users.*
|
10
|
+
from users, user_groups_users
|
11
|
+
where users.id = user_groups_users.user_id
|
12
|
+
and user_groups_users.user_group_id = #{self.id}
|
13
|
+
SQL
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<h1>Listing Permissions</h1>
|
2
|
+
|
3
|
+
<table>
|
4
|
+
<tr>
|
5
|
+
<th>Name</th>
|
6
|
+
</tr>
|
7
|
+
|
8
|
+
<%% for permission in @permissions %>
|
9
|
+
<tr>
|
10
|
+
<td><%%=h permission.name %></td>
|
11
|
+
<td><%%= link_to 'Show', <%= namespace.blank? ? 'permission_path(permission)' : "#{namespace}_permission_path(permission)" %> %></td>
|
12
|
+
</tr>
|
13
|
+
<%% end %>
|
14
|
+
</table>
|
15
|
+
|
16
|
+
<br />
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<p>
|
2
|
+
<b>Name</b><br />
|
3
|
+
<%%= h @permission.name %>
|
4
|
+
</p>
|
5
|
+
<p>
|
6
|
+
<b>Access rights:</b><br />
|
7
|
+
<%%
|
8
|
+
Lockdown::System.access_rights_for_permission(@permission).each do |access_right|
|
9
|
+
%>
|
10
|
+
<%%= access_right %><br/>
|
11
|
+
<%%
|
12
|
+
end
|
13
|
+
%>
|
14
|
+
</p>
|
15
|
+
<p>
|
16
|
+
<b>Users with permission:</b><br />
|
17
|
+
<%%
|
18
|
+
@permission.all_users.each do |user|
|
19
|
+
%>
|
20
|
+
<%%= link_to_or_show(user.full_name, <%= namespace.blank? ? 'user' : "#{namespace}_user_path(user)" %>) %><br/>
|
21
|
+
<%%
|
22
|
+
end
|
23
|
+
%>
|
24
|
+
</p>
|
25
|
+
|
26
|
+
<%%= link_to 'Back', <%= namespace.blank? ? 'permissions_path' : "#{namespace}_permissions_path" %> %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%%= flash[:notice] if flash[:notice] %>
|
2
|
+
<%%= flash[:error] if flash[:error] %>
|
3
|
+
|
4
|
+
<%% form_tag sessions_path do -%>
|
5
|
+
<p><label for="login">Login</label><br/>
|
6
|
+
<%%= text_field_tag 'login' %></p>
|
7
|
+
|
8
|
+
<p><label for="password">Password</label><br/>
|
9
|
+
<%%= password_field_tag 'password' %></p>
|
10
|
+
|
11
|
+
<p><%%= submit_tag 'Log in' %></p>
|
12
|
+
<%% end -%>
|