ixtlan-guard 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate guard Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,22 @@
1
+ module Ixtlan
2
+ class ControllerGenerator < Rails::Generators::NamedBase
3
+
4
+ source_root File.expand_path('../../templates', __FILE__)
5
+
6
+ argument :actions, :type => :array, :default => [], :banner => "action action"
7
+
8
+ check_class_collision :suffix => "Guard"
9
+
10
+ def create_guard_file
11
+ template 'guard.rb', File.join('app', 'guards', class_path, "#{file_name}_guard.rb")
12
+ end
13
+
14
+ def guard_class_name
15
+ class_name
16
+ end
17
+
18
+ def aliases
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate guard Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,28 @@
1
+ require 'rails/generators/resource_helpers'
2
+ module Ixtlan
3
+ class ScaffoldGenerator < Rails::Generators::NamedBase
4
+ include Rails::Generators::ResourceHelpers
5
+
6
+ source_root File.expand_path('../../templates', __FILE__)
7
+
8
+ # check_class_collision :suffix => "Guard"
9
+
10
+ def create_guard_files
11
+ puts "ASD"
12
+ template 'guard.rb', File.join('app', 'guards', class_path, "#{plural_file_name}_guard.rb")
13
+ end
14
+
15
+ def guard_class_name
16
+ controller_class_name
17
+ end
18
+
19
+ def aliases
20
+ { :new => :create, :edit => :update }
21
+ end
22
+
23
+ def actions
24
+ ['index', 'show', 'create', 'update', 'destroy']
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ <h1>Editing <%= singular_table_name %></h1>
2
+
3
+ <%%= render 'form' %>
4
+
5
+ <%% if allowed?(:<%= table_name %>, :show) %>
6
+ <%%= link_to 'Show', @<%= singular_table_name %> %> |
7
+ <%% end %>
8
+ <%% if allowed?(:<%= table_name %>, :index) %>
9
+ <%%= link_to 'Back', <%= index_helper %>_path %>
10
+ <%% end %>
@@ -0,0 +1,13 @@
1
+ class <%= guard_class_name %>Guard
2
+ def initialize(guard)
3
+ #guard.name = "<%= plural_file_name %>"
4
+ <% if aliases -%>
5
+ guard.aliases = <%= aliases.inspect %>
6
+ <% end -%>
7
+ guard.action_map= {
8
+ <% for action in actions -%>
9
+ :<%= action %> => [],
10
+ <% end -%>
11
+ }
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ <h1>Listing <%= plural_table_name %></h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <% for attribute in attributes -%>
6
+ <th><%= attribute.human_name %></th>
7
+ <% end -%>
8
+ <th></th>
9
+ <th></th>
10
+ <th></th>
11
+ </tr>
12
+
13
+ <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %>
14
+ <tr>
15
+ <% for attribute in attributes -%>
16
+ <td><%%= <%= singular_table_name %>.<%= attribute.name %> %></td>
17
+ <% end -%>
18
+ <%% if allowed?(:<%= table_name %>, :show) %>
19
+ <td><%%= link_to 'Show', <%= singular_table_name %> %></td>
20
+ <%% end %>
21
+ <%% if allowed?(:<%= table_name %>, :update) %>
22
+ <td><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %></td>
23
+ <%% end %>
24
+ <%% if allowed?(:<%= table_name %>, :destroy) %>
25
+ <td><%%= link_to 'Destroy', <%= singular_table_name %>, :confirm => 'Are you sure?', :method => :delete %></td>
26
+ <%% end %>
27
+ </tr>
28
+ <%% end %>
29
+ </table>
30
+
31
+ <br />
32
+
33
+ <%% if allowed?(:<%= table_name %>, :create) %>
34
+ <%%= link_to 'New <%= human_name %>', new_<%= singular_table_name %>_path %>
35
+ <%% end %>
@@ -0,0 +1,7 @@
1
+ <h1>New <%= singular_table_name %></h1>
2
+
3
+ <%%= render 'form' %>
4
+
5
+ <%% if allowed?(:<%= table_name %>, :index) %>
6
+ <%%= link_to 'Back', <%= index_helper %>_path %>
7
+ <%% end %>
@@ -0,0 +1,16 @@
1
+ <p id="notice"><%%= notice %></p>
2
+
3
+ <% for attribute in attributes -%>
4
+ <p>
5
+ <b><%= attribute.human_name %>:</b>
6
+ <%%= @<%= singular_table_name %>.<%= attribute.name %> %>
7
+ </p>
8
+
9
+ <% end -%>
10
+
11
+ <%% if allowed?(:<%= table_name %>, :update) %>
12
+ <%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> |
13
+ <%% end %>
14
+ <%% if allowed?(:<%= table_name %>, :index) %>
15
+ <%%= link_to 'Back', <%= index_helper %>_path %>
16
+ <%% end %>
@@ -0,0 +1,23 @@
1
+ # use this extended copy of Rails::Generators::ScaffoldGenerator
2
+ # since the search path is the following:
3
+ # ["scaffold:scaffold", "rails:scaffold", "scaffold"]
4
+ # which allows to override orignal generator
5
+ # adding a Rails::Generators::ScaffoldGenerator.hook_for did not work
6
+ # since it looses the ORM config somehow
7
+ require 'rails/generators/rails/resource/resource_generator'
8
+ module Rails
9
+ module Generators
10
+ class ScaffoldGenerator < ResourceGenerator #metagenerator
11
+
12
+ remove_hook_for :resource_controller
13
+ remove_class_option :actions
14
+
15
+ hook_for :scaffold_controller, :required => true, :in => :rails
16
+ hook_for :stylesheets, :in => :rails
17
+
18
+ hook_for :ixtlan, :type => :boolean, :default => true do |controller|
19
+ invoke controller, [class_name]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ require 'ixtlan/guard'
2
+ if defined?(Rails)
3
+ require 'ixtlan/guard_railtie'
4
+ require 'ixtlan/rails_integration'
5
+ end
@@ -0,0 +1,159 @@
1
+ require 'logger'
2
+ module Ixtlan
3
+ class ControllerGuard
4
+
5
+ attr_accessor :name, :action_map, :aliases
6
+
7
+ def initialize(name)
8
+ @name = name.sub(/_guard$/, '').to_sym
9
+ class_name = name.split(/\//).collect { |part| part.split("_").each { |pp| pp.capitalize! }.join }.join("::")
10
+ Object.const_get(class_name).new(self)
11
+ end
12
+
13
+ def name=(name)
14
+ @name = name.to_sym
15
+ end
16
+
17
+ def aliases=(map)
18
+ @aliases = symbolize(map)
19
+ end
20
+
21
+ def action_map=(map)
22
+ @action_map = symbolize(map)
23
+ end
24
+
25
+ private
26
+
27
+ def symbolize(h)
28
+ result = {}
29
+
30
+ h.each do |k, v|
31
+ if v.is_a?(Hash)
32
+ result[k.to_sym] = symbolize_keys(v) unless v.size == 0
33
+ elsif v.is_a?(Array)
34
+ val = []
35
+ v.each {|vv| val << vv.to_sym }
36
+ result[k.to_sym] = val
37
+ else
38
+ result[k.to_sym] = v.to_sym
39
+ end
40
+ end
41
+
42
+ result
43
+ end
44
+
45
+ end
46
+
47
+ class Guard
48
+
49
+ attr_accessor :logger, :guard_dir, :superuser, :block
50
+
51
+ def initialize(logger = Logger.new(STDOUT), superuser = :root, guard_dir = File.join("app", "guards"), &block)
52
+ @map = {}
53
+ @aliases = {}
54
+
55
+ @block =
56
+ if block
57
+ block
58
+ else
59
+ Proc.new do |controller|
60
+ # get the groups of the current_user
61
+ user = controller.send(:current_user) if controller.respond_to? :current_user
62
+ user.groups if user
63
+ end
64
+ end
65
+ @logger = logger
66
+ @superuser = superuser
67
+ @guard_dir = guard_dir
68
+ end
69
+
70
+ def setup
71
+ if File.exists?(@guard_dir)
72
+ Dir.new(guard_dir).to_a.each do |f|
73
+ if f.match(".rb$")
74
+ require(File.join(guard_dir, f))
75
+ controller_guard = ControllerGuard.new(f.sub(/.rb$/, ''))
76
+ register(controller_guard)
77
+ end
78
+ end
79
+ logger.debug("initialized guard . . .")
80
+ else
81
+ raise GuardException.new("guard directory #{guard_dir} not found, skip loading")
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def register(controller_guard)
88
+ msg = controller_guard.action_map.collect{ |k,v| "\n\t#{k} => [#{v.join(',')}]"}
89
+ @logger.debug("#{controller_guard.name} guard: #{msg}")
90
+ @map[controller_guard.name] = controller_guard.action_map
91
+ @aliases[controller_guard.name] = controller_guard.aliases || {}
92
+ end
93
+
94
+ public
95
+
96
+ def block_groups(groups)
97
+ @blocked = (groups || []).collect { |g| g.to_sym}
98
+ end
99
+
100
+ def blocked
101
+ @blocked ||= []
102
+ end
103
+
104
+ def current_user_restricted?(controller)
105
+ groups = @block.call(controller)
106
+ if groups
107
+ p groups
108
+ p blocked
109
+ p groups.select { |g| !blocked.member?(g.to_sym) }
110
+ groups.select { |g| !blocked.member?(g.to_sym) }.size < groups.size
111
+ else
112
+ nil
113
+ end
114
+ end
115
+
116
+ def check(controller, resource, action, &block)
117
+ groups = @block.call(controller)
118
+ if groups.nil?
119
+ @logger.debug("check #{resource}##{action}: not authenticated")
120
+ return true
121
+ end
122
+ resource = resource.to_sym
123
+ action = action.to_sym
124
+ if (@map.key? resource)
125
+ action = @aliases[resource][action] || action
126
+ allowed = @map[resource][action]
127
+ if (allowed.nil?)
128
+ @logger.warn("unknown action '#{action}' for controller '#{resource}'")
129
+ raise ::Ixtlan::GuardException.new("unknown action '#{action}' for controller '#{resource}'")
130
+ else
131
+ allowed << @superuser unless allowed.member? @superuser
132
+ allow_all_groups = allowed.member?(:*)
133
+ if(allow_all_groups && block.nil?)
134
+ @logger.debug("check #{resource}##{action}: allowed for all")
135
+ return true
136
+ else
137
+ groups.each do |group|
138
+ if (allow_all_groups || allowed.member?(group.to_sym)) && !blocked.member?(group.to_sym)
139
+ if(block.nil? || block.call(group))
140
+ @logger.debug("check #{resource}##{action}: true")
141
+ return true
142
+ end
143
+ end
144
+ end
145
+ end
146
+ @logger.debug("check #{resource}##{action}: false")
147
+ return false
148
+ end
149
+ else
150
+ @logger.warn("unknown controller for '#{resource}'")
151
+ raise ::Ixtlan::GuardException.new("unknown controller for '#{resource}'")
152
+ end
153
+ end
154
+ end
155
+
156
+ class GuardException < Exception; end
157
+ class PermissionDenied < GuardException; end
158
+ end
159
+
@@ -0,0 +1,43 @@
1
+ require 'rails'
2
+ require 'ixtlan/guard'
3
+ require 'logger'
4
+
5
+ class GuardRailtie < Rails::Railtie
6
+
7
+ config.before_configuration do |app|
8
+ app.config.class.class_eval do
9
+ attr_accessor :guard
10
+ end
11
+ app.config.guard =
12
+ Ixtlan::Guard.new(Logger.new(STDERR),
13
+ :root,
14
+ File.join(Rails.root, "app", "guards"))
15
+ end
16
+
17
+ config.after_initialize do |app|
18
+ logger = app.config.logger || Rails.logger || Logger.new(STDERR)
19
+ app.config.guard.logger = logger
20
+ begin
21
+ app.config.guard.setup
22
+ rescue Ixtlan::GuardException => e
23
+ logger.warn e.message
24
+ end
25
+ end
26
+
27
+ config.generators do
28
+ require 'rails/generators'
29
+ require 'rails/generators/rails/controller/controller_generator'
30
+ require 'rails/generators/erb/scaffold/scaffold_generator'
31
+ Rails::Generators::ControllerGenerator.hook_for :ixtlan, :type => :boolean, :default => true do |controller|
32
+ invoke controller, [ class_name, actions ]
33
+ end
34
+ Erb::Generators::ScaffoldGenerator.source_paths.insert(0, File.expand_path('../../generators/ixtlan/templates', __FILE__))
35
+ #require 'rails/generators/rails/scaffold/scaffold_generator'
36
+ # somehow the check is before the value is set,
37
+ # so just ignore the require flag
38
+ #Rails::Generators::ScaffoldGenerator.class_options[:orm].instance_variable_set(:@required, false)
39
+ #Rails::Generators::ScaffoldGenerator.hook_for :ixtlan, :as => :scaffold, :type => :boolean, :default => true do |controller|
40
+ # invoke controller, [class_name]
41
+ #end
42
+ end
43
+ end
@@ -0,0 +1,55 @@
1
+ require 'ixtlan/guard'
2
+ module Ixtlan
3
+ module ActionController #:nodoc:
4
+ module Guard #:nodoc:
5
+ def self.included(base)
6
+ base.send(:include, InstanceMethods)
7
+ end
8
+ module InstanceMethods #:nodoc:
9
+
10
+ protected
11
+
12
+ def guard
13
+ Rails.configuration.guard
14
+ end
15
+
16
+ def authorization(&block)
17
+ resource_authorization(params[:controller], params[:action], &block)
18
+ end
19
+
20
+ def resource_authorization(resource, action, &block)
21
+ unless guard.check(self, resource, action, &block)
22
+ raise ::Ixtlan::PermissionDenied.new("permission denied for '#{resource}##{action}'")
23
+ end
24
+ true
25
+ end
26
+
27
+ def allowed?(action, &block)
28
+ guard.check(self, params[:controller], action, &block)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ module Allowed #:nodoc:
35
+ # Inclusion hook to make #allowed available as method
36
+ def self.included(base)
37
+ base.send(:include, InstanceMethods)
38
+ end
39
+
40
+ module InstanceMethods #:nodoc:
41
+ def allowed?(resource, action, &block)
42
+ controller.send(:guard).check(controller, resource, action, &block)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ ActionController::Base.send(:include, Ixtlan::ActionController::Guard)
49
+ ActionController::Base.send(:before_filter, :authorization)
50
+ ActionView::Base.send(:include, Ixtlan::Allowed)
51
+ module Erector
52
+ class Widget
53
+ include Ixtlan::Allowed
54
+ end
55
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+ require 'ixtlan/guard'
3
+
4
+ describe Ixtlan::Guard do
5
+
6
+ before :all do
7
+ @guard = Ixtlan::Guard.new(Logger.new(STDOUT),
8
+ :root,
9
+ File.join(File.dirname(__FILE__), "guards") )
10
+
11
+ @guard.setup
12
+ @current_user = Object.new
13
+ def @current_user.groups(g = nil)
14
+ @g = g if g
15
+ @g || []
16
+ end
17
+
18
+ @controller = Object.new
19
+ def @controller.current_user(u = nil)
20
+ @u = u if u
21
+ @u
22
+ end
23
+ @controller.current_user( @current_user )
24
+ end
25
+
26
+ it 'should fail with missing guard dir' do
27
+ lambda {Ixtlan::Guard.new(Logger.new(STDOUT),
28
+ :root,
29
+ "does_not_exists").setup }.should raise_error(Ixtlan::GuardException)
30
+ end
31
+
32
+ it 'should initialize' do
33
+ @guard.should_not be_nil
34
+ end
35
+
36
+ it 'should pass check without user' do
37
+ controller = Object.new
38
+ def controller.current_user
39
+ end
40
+ @guard.check(controller, :none, :something).should be_true
41
+ end
42
+
43
+ it 'should pass check with user being root' do
44
+ @current_user.groups([:root])
45
+ @guard.check(@controller, :users, :show).should be_true
46
+ end
47
+
48
+ it 'should not pass check with user - no groups' do
49
+ @current_user.groups([])
50
+ @guard.check(@controller, :users, :show).should be_false
51
+ end
52
+
53
+ it 'should pass unguarded check with user - no groups' do
54
+ @current_user.groups([])
55
+ @guard.check(@controller, :users, :index).should be_true
56
+ end
57
+
58
+ it 'should pass check with user on aliased action' do
59
+ @current_user.groups([:users])
60
+ @guard.check(@controller, :users, :edit).should be_true
61
+ end
62
+
63
+ it 'should pass check with user' do
64
+ @current_user.groups([:users])
65
+ @guard.check(@controller, :users, :update).should be_true
66
+ end
67
+
68
+ it 'should not pass check with user' do
69
+ @current_user.groups([:accounts])
70
+ @guard.check(@controller, :users, :update).should be_false
71
+ end
72
+
73
+ it 'should pass check with user with passing extra check' do
74
+ @current_user.groups([:users])
75
+ @guard.check(@controller, :users, :update) do |g|
76
+ true
77
+ end.should be_true
78
+ end
79
+
80
+ it 'should not pass check with user with failing extra check' do
81
+ @current_user.groups([:users])
82
+ @guard.check(@controller, :users, :update) do |g|
83
+ false
84
+ end.should be_false
85
+ end
86
+
87
+ it 'should raise exception on unknown action' do
88
+ lambda {@guard.check(@controller, :users, :unknown_action) }.should raise_error(Ixtlan::GuardException)
89
+ end
90
+
91
+ it 'should raise exception on unknown resource' do
92
+ lambda {@guard.check(@controller, :unknown_resource, :update) }.should raise_error(Ixtlan::GuardException)
93
+ end
94
+ end
@@ -0,0 +1,13 @@
1
+ class UsersGuard
2
+ def initialize(guard)
3
+ guard.name = "users"
4
+ guard.aliases= {:edit => :update}
5
+ guard.action_map= {
6
+ :index => [:*],
7
+ :show => [:users],
8
+ :create => [:users],
9
+ :update => [:users],
10
+ :destroy => [:users]
11
+ }
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ require 'spec_helper'
2
+ require 'ixtlan/guard_railtie'
@@ -0,0 +1,2 @@
1
+ lib_path = (Pathname(__FILE__).dirname.parent.expand_path + 'lib').to_s
2
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ixtlan-guard
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - mkristian
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-10-17 00:00:00 +05:30
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rails
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 3
29
+ - 0
30
+ - 0
31
+ version: 3.0.0
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 3
44
+ - 1
45
+ version: 1.3.1
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: cucumber
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ - 9
58
+ - 2
59
+ version: 0.9.2
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ - 8
72
+ - 7
73
+ version: 0.8.7
74
+ type: :development
75
+ version_requirements: *id004
76
+ description: simple authorization framework for rails controllers
77
+ email:
78
+ - m.kristian@web.de
79
+ executables: []
80
+
81
+ extensions: []
82
+
83
+ extra_rdoc_files: []
84
+
85
+ files:
86
+ - lib/ixtlan-guard.rb
87
+ - lib/generators/scaffold/scaffold/scaffold_generator.rb
88
+ - lib/generators/ixtlan/controller/USAGE
89
+ - lib/generators/ixtlan/controller/controller_generator.rb
90
+ - lib/generators/ixtlan/scaffold/USAGE
91
+ - lib/generators/ixtlan/scaffold/scaffold_generator.rb
92
+ - lib/generators/ixtlan/templates/new.html.erb
93
+ - lib/generators/ixtlan/templates/show.html.erb
94
+ - lib/generators/ixtlan/templates/guard.rb
95
+ - lib/generators/ixtlan/templates/edit.html.erb
96
+ - lib/generators/ixtlan/templates/index.html.erb
97
+ - lib/ixtlan/guard_railtie.rb
98
+ - lib/ixtlan/rails_integration.rb
99
+ - lib/ixtlan/guard.rb
100
+ - spec/guard_spec.rb
101
+ - spec/spec_helper.rb
102
+ - spec/railtie_spec.rb
103
+ - spec/guards/users_guard.rb
104
+ has_rdoc: true
105
+ homepage: http://github.com/mkristian/ixtlan-guard
106
+ licenses: []
107
+
108
+ post_install_message:
109
+ rdoc_options:
110
+ - --main
111
+ - README.textile
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ segments:
126
+ - 0
127
+ version: "0"
128
+ requirements: []
129
+
130
+ rubyforge_project:
131
+ rubygems_version: 1.3.6
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: guard your controller actions
135
+ test_files:
136
+ - spec/guard_spec.rb
137
+ - spec/railtie_spec.rb