turnstile 0.1.0

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/Manifest ADDED
@@ -0,0 +1,7 @@
1
+ README.rdoc
2
+ Rakefile
3
+ lib/turnstile.rb
4
+ lib/turnstile/authorization.rb
5
+ lib/turnstile/role.rb
6
+ lib/turnstile/rule.rb
7
+ Manifest
data/README.rdoc ADDED
@@ -0,0 +1,57 @@
1
+ Turnstile is a simple authorization module.
2
+ With turnstile you'll be able to define rules for each role to access your controllers and views.
3
+
4
+ = Roles, Rules and Privileges
5
+
6
+ You can define all roles, all rules and all privileges in the config file, placed in config/initializers/turnstile.rb
7
+
8
+ = Privileges
9
+
10
+
11
+ privilege :read do
12
+ allows_to :show, :index
13
+ denies_to :destroy, :create
14
+ end
15
+
16
+ privilege :manage do
17
+ allows_to :create, :new
18
+ allows_to :destroy
19
+ end
20
+
21
+
22
+ = Rules to Roles
23
+
24
+ role :reader do
25
+ can :read => :posts
26
+ can :read => :comments
27
+ end
28
+
29
+ role :admin do
30
+ inherits :reader
31
+ can :manage => :posts
32
+ end
33
+
34
+
35
+ = The Default Role
36
+
37
+
38
+ You need to set a role to be used when the current user has no role
39
+
40
+ default :reader
41
+
42
+
43
+ An example of config file can be found in config/initializers/turnstile.rb in this repo.
44
+
45
+ = The User Model
46
+
47
+ To set the model, so far it is hardcoded, so you need a string column called
48
+ user_role
49
+ in your user model, and be sure to have a method that returns the current user, called
50
+ current_user
51
+
52
+ = Controllers
53
+ For each controller that you want to monirate just call:
54
+
55
+ before_filter :verify_role_permissions!
56
+
57
+
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('turnstile', '0.1.0') do |p|
6
+ p.description = "Simple authorization for rails"
7
+ p.url = "http://github.com/milare/turnstile"
8
+ p.author = "Bruno Milare"
9
+ p.email = "milare@gmail.com"
10
+ p.ignore_pattern = ["spec/*", "config/initializers/*"]
11
+ p.development_dependencies = []
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
@@ -0,0 +1,155 @@
1
+ # Turnstile::Authorization
2
+ # Module that is used as interface to the application
3
+ module Turnstile
4
+ module Authorization
5
+
6
+ # Keep track of all permissions defined
7
+ # A permission is defined in the setup with such as:
8
+ #
9
+ # privilege :manage do
10
+ # allows_to :create, :new
11
+ # end
12
+ @@permissions = {}
13
+
14
+ # used in tests so far, to perform the setup
15
+ def self.read_config_file
16
+ require File.expand_path(File.dirname(__FILE__) + '/../../config/initializers/turnstile')
17
+ end
18
+
19
+ # Run the config file with all definitions
20
+ def self.setup(&block)
21
+ yield if block_given?
22
+ end
23
+
24
+ # Used by tests to reset all configurations done
25
+ def self.reset
26
+ @@permissions = {}
27
+ Role.clear
28
+ end
29
+
30
+ # Finds a permission
31
+ # Turnstile::Authorization.find_permission(:manage)
32
+ def self.find_permission(permission_name)
33
+ @@permissions[permission_name]
34
+ end
35
+
36
+ # From setup defines the default role
37
+ # If the role is not found tries to define
38
+ # common names for guests
39
+ # The default role is used when there is no current role
40
+ def default(role_str)
41
+ role = Role.find(role_str.to_sym)
42
+ if !role
43
+ role ||= Role.find(:guest)
44
+ role ||= Role.find(:visitor)
45
+ if !role
46
+ Role.set_default_role(role)
47
+ else
48
+ Role.set_default_role(Role.first)
49
+ end
50
+ else
51
+ Role.set_default_role(role)
52
+ end
53
+ end
54
+
55
+
56
+ # Method used in each controller that requires authorization
57
+ # Actually it handles the requests performed by the controller
58
+ # and then check if the current_role id allowed to perfom the action
59
+ def verify_role_permissions!
60
+ if request || request.params
61
+ action = request.params[:action] ? request.params[:action] : nil
62
+ controller = request.params[:controller] ? request.params[:controller] : nil
63
+ if action and controller
64
+ if !current_role.is_allowed_to? action, controller
65
+ flash[:alert] = "Unauthorized action"
66
+ redirect_to root_path
67
+ end
68
+ else
69
+ redirect_to root_path
70
+ end
71
+ else
72
+ redirect_to root_path
73
+ end
74
+ end
75
+
76
+ # Returns the default role in this scope
77
+ def default_role
78
+ Role.default_role
79
+ end
80
+
81
+ # Helper to get current_role
82
+ # TODO: Find a way to get the current_user role in a dynamic way
83
+ # This way like current_user.user_role is too hardcoded
84
+ def current_role
85
+ current_role = current_user ? Role.find(current_user.user_role.to_sym) : nil
86
+ current_role ||= Role.default_role
87
+ end
88
+
89
+ # Set the current_role
90
+ def current_role=(role)
91
+ current_role = role
92
+ end
93
+
94
+ # Methods to define a permission
95
+ # privilege :manage do
96
+ # allows_to :create, :new
97
+ # denies_to :destroy
98
+ # end
99
+ def privilege(name, &block)
100
+ @current_permission = name
101
+ @@permissions[@current_permission] = {}
102
+ yield if block_given?
103
+ end
104
+
105
+ def allows_to(*actions)
106
+ @@permissions[@current_permission][:allow] ||= []
107
+ actions.each do |action|
108
+ @@permissions[@current_permission][:allow] << action
109
+ end
110
+ end
111
+
112
+ def denies_to(*actions)
113
+ @@permissions[@current_permission][:deny] ||= []
114
+ actions.each do |action|
115
+ @@permissions[@current_permission][:deny] << action
116
+ end
117
+ end
118
+
119
+ # Methods to set a privilege(permission) to a role
120
+ # role :admin do
121
+ # can :manage => :posts
122
+ # inherits :reader
123
+ # end
124
+ def role(role, &block)
125
+ @current_role = Role.find(role)
126
+ @current_role ||= Role.new(:name => role, :rules => [])
127
+ yield if block_given?
128
+ end
129
+
130
+ def inherits(role)
131
+ parent = Role.find(role)
132
+ parent ? @current_role.merge_rules(parent.rules) : @current_role.rules
133
+ end
134
+
135
+ def can(rules_set)
136
+ rules = []
137
+ rules_set.keys.each do |permission|
138
+ actions = Authorization.find_permission(permission)
139
+ controller = rules_set[permission]
140
+ if actions[:allow]
141
+ actions[:allow].each do |action|
142
+ rules << Rule.new(:action => action.to_s, :controller => controller.to_s, :allow => true, :active => true)
143
+ end
144
+ end
145
+ if actions[:deny]
146
+ actions[:deny].each do |action|
147
+ rules << Rule.new(:action => action.to_s, :controller => controller.to_s, :allow => false, :active => true)
148
+ end
149
+ end
150
+ end
151
+ @current_role.merge_rules(rules)
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,133 @@
1
+ # Role class
2
+ # Provides all needed methods to handle a role and its rules
3
+ class Role
4
+
5
+ attr_accessor :name, :rules
6
+
7
+ # Class variable to keep control of all roles
8
+ @@roles = {}
9
+
10
+ # Class variable to keep the default role, it means that if
11
+ # there is no current_role than the default is used
12
+ @@default = nil
13
+
14
+ # Class methods
15
+ # Adds a role to the roles hash
16
+ def self.add_role(role)
17
+ @@roles[role.name.to_sym] = role
18
+ end
19
+
20
+ def self.all_roles
21
+ @@roles
22
+ end
23
+
24
+ # Find a role by its name
25
+ # Role.find(:admin)
26
+ # returns Role or nil
27
+ def self.find(role_sym)
28
+ @@roles[role_sym]
29
+ end
30
+
31
+ def self.first
32
+ @@roles.first
33
+ end
34
+
35
+ # Remove all role from memory, used for tests so far
36
+ def self.clear
37
+ @@roles = {}
38
+ end
39
+
40
+ def self.set_default_role(role)
41
+ @@default = role
42
+ end
43
+
44
+ def self.default_role
45
+ @@default
46
+ end
47
+
48
+ def initialize(role)
49
+ @name = role[:name]
50
+ @rules = role[:rules]
51
+
52
+ # Helper for each initialized role
53
+ # is_role? for a role with name 'role'
54
+ # is_admin? when admin role is instantiated
55
+ Role.class_eval <<-METHOD
56
+ def is_#{@name}?
57
+ @name == '#{@name}'
58
+ end
59
+ METHOD
60
+
61
+ Role.add_role self
62
+ end
63
+
64
+
65
+ # Return all(array) controllers that an user can access
66
+ def accessible_controllers
67
+ controllers = []
68
+ @rules.each do |rule|
69
+ if rule.allows?
70
+ controllers << rule.controller
71
+ end
72
+ end
73
+ controllers.uniq
74
+ end
75
+
76
+ # Return the allowed actions in a controller for the current_role
77
+ def allowed_actions_in(controller)
78
+ actions = []
79
+ @rules.each do |rule|
80
+ if rule.controller == controller.to_s and rule.allows?
81
+ actions << rule.action
82
+ end
83
+ end
84
+ actions.uniq
85
+ end
86
+
87
+ # Return the denied actions in a controller for the current_role
88
+ def denied_actions_in(controller)
89
+ actions = []
90
+ @rules.each do |rule|
91
+ if rule.controller == controller.to_s and rule.denies?
92
+ actions << rule.action
93
+ end
94
+ end
95
+ actions.uniq
96
+ end
97
+
98
+ # Return if a role is allowed to perform an action in a controller
99
+ # current_role.is_allowed_to? :create, :posts
100
+ def is_allowed_to?(action, controller)
101
+ @rules.each do |rule|
102
+ if rule.action == action.to_s and rule.controller == controller.to_s
103
+ return rule.allows?
104
+ end
105
+ end
106
+ false
107
+ end
108
+
109
+ # Merges a set of rules with the current_role rules
110
+ # current_role.merge_rules(set_of_rules[])
111
+ # Used to apply rules to an user and for inheritance
112
+ def merge_rules(new_rules)
113
+ self.rules ||= []
114
+ new_set = new_rules
115
+ overwritten_set = remove_set = []
116
+
117
+ self.rules.each do |rule|
118
+ new_rules.each do |included_rule|
119
+ if included_rule.action == rule.action and included_rule.controller == rule.controller
120
+ overwritten_set << included_rule
121
+ remove_set << rule
122
+ new_set.delete(included_rule)
123
+ end
124
+ end
125
+ end
126
+ self.rules = self.rules - remove_set + overwritten_set + new_set
127
+ self.rules
128
+ end
129
+
130
+ end
131
+
132
+
133
+
@@ -0,0 +1,34 @@
1
+ # Rule class
2
+ # A simple to class to manipulate the array of rules
3
+ class Rule
4
+
5
+ attr_accessor :action, :controller, :allow, :active
6
+
7
+ def initialize(rules)
8
+
9
+ @action = rules[:action]
10
+ @controller = rules[:controller]
11
+ @allow = rules[:allow]
12
+ @active = rules[:active]
13
+ end
14
+
15
+ # The current rule allows or denies some action?
16
+ def allow_or_deny?
17
+ @allow == true ? :allow : :deny
18
+ end
19
+
20
+ def is_active?
21
+ @active
22
+ end
23
+
24
+ def allows?
25
+ @allow ? true : false
26
+ end
27
+
28
+ def denies?
29
+ @allow ? false : true
30
+ end
31
+
32
+
33
+
34
+ end
data/lib/turnstile.rb ADDED
@@ -0,0 +1,3 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/turnstile/role")
2
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/turnstile/rule")
3
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/turnstile/authorization")
data/turnstile.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{turnstile}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Bruno Milare"]
9
+ s.date = %q{2010-08-25}
10
+ s.description = %q{Simple authorization for rails}
11
+ s.email = %q{milare@gmail.com}
12
+ s.extra_rdoc_files = ["README.rdoc", "lib/turnstile.rb", "lib/turnstile/authorization.rb", "lib/turnstile/role.rb", "lib/turnstile/rule.rb"]
13
+ s.files = ["README.rdoc", "Rakefile", "lib/turnstile.rb", "lib/turnstile/authorization.rb", "lib/turnstile/role.rb", "lib/turnstile/rule.rb", "Manifest", "turnstile.gemspec"]
14
+ s.homepage = %q{http://github.com/milare/turnstile}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Turnstile", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{turnstile}
18
+ s.rubygems_version = %q{1.3.7}
19
+ s.summary = %q{Simple authorization for rails}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ else
27
+ end
28
+ else
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: turnstile
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Bruno Milare
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-25 00:00:00 -03:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Simple authorization for rails
23
+ email: milare@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.rdoc
30
+ - lib/turnstile.rb
31
+ - lib/turnstile/authorization.rb
32
+ - lib/turnstile/role.rb
33
+ - lib/turnstile/rule.rb
34
+ files:
35
+ - README.rdoc
36
+ - Rakefile
37
+ - lib/turnstile.rb
38
+ - lib/turnstile/authorization.rb
39
+ - lib/turnstile/role.rb
40
+ - lib/turnstile/rule.rb
41
+ - Manifest
42
+ - turnstile.gemspec
43
+ has_rdoc: true
44
+ homepage: http://github.com/milare/turnstile
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --line-numbers
50
+ - --inline-source
51
+ - --title
52
+ - Turnstile
53
+ - --main
54
+ - README.rdoc
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 11
72
+ segments:
73
+ - 1
74
+ - 2
75
+ version: "1.2"
76
+ requirements: []
77
+
78
+ rubyforge_project: turnstile
79
+ rubygems_version: 1.3.7
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Simple authorization for rails
83
+ test_files: []
84
+