acl_system2 0.2.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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006 Ezra Zygmuntowicz & Fabien Franzen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,129 @@
1
+ Welcome to the acl_system plugin for rails. This plugin is designed to give you a
2
+ flexible declarative way of protecting your various controller actions using roles.
3
+ It's made to sit on top of any authentication framework that follows a few conventions.
4
+ You will need to have a `current_user` method that returns the currently logged in user.
5
+ And you will need to make your `User` or `Account` model(or whatever you named it) have a
6
+ `has_and_belongs_to_many :roles`. So you need a model called `Role` that has a `title` attribute.
7
+ Once these two things are satisfied you can use this plugin.
8
+
9
+ So lets take a look at the sugar you get from using this plugin. Keep in mind that the
10
+ `!blacklist` part isn’t really necessary here. I was just showing it as an example of how
11
+ flexible the permissions string logic parser is.
12
+
13
+ ```ruby
14
+ class PostController < ApplicationController
15
+ before_filter :login_required, :except => [:list, :index]
16
+ access_control [:new, :create, :update, :edit] => '(admin | user | moderator)',
17
+ :delete => 'admin & (!moderator & !blacklist)'
18
+ ```
19
+ Of course you can define them all separately if they differ at all.
20
+
21
+ ```ruby
22
+ class PostController < ApplicationController
23
+ before_filter :login_required, :except => [:list, :index]
24
+ access_control :new => '(admin | user | moderator) & !blacklist',
25
+ :create => 'admin & !blacklist',
26
+ :edit => '(admin | moderator) & !blacklist',
27
+ :update => '(admin | moderator) & !blacklist',
28
+ :delete => 'admin & (!moderator | !blacklist)'
29
+ ```
30
+
31
+ And you can also use `:DEFAULT` if you have a lot of actions that need the same permissions.
32
+
33
+ ```ruby
34
+ class PostController < ApplicationController
35
+ before_filter :login_required, :except => [:list, :index]
36
+ access_control :DEFAULT => '!guest'
37
+ [:new, :create, :update, :edit] => '(admin | user | moderator)',
38
+ :delete => 'admin & (!moderator & !blacklist)'
39
+ ```
40
+
41
+ There are two callback methods you can use to define your own success and failure behaviours.
42
+ If you define `permission_granted` and/or `permission_denied` as protected methods in your controller you
43
+ can redirect or render and error page or whatever else you might want to do if access is allowed
44
+ or denied.
45
+
46
+ ```ruby
47
+ class PostController < ApplicationController
48
+ before_filter :login_required, :except => [:list, :index]
49
+ access_control :DEFAULT => '!guest'
50
+ [:new, :create, :update, :edit] => '(admin | user | moderator)',
51
+ :delete => 'admin & (!moderator & !blacklist)'
52
+
53
+ # the rest of your controller here
54
+
55
+ protected
56
+
57
+ def permission_denied
58
+ flash[:notice] = "You don't have privileges to access this action"
59
+ return redirect_to :action => 'denied'
60
+ end
61
+
62
+ def permission_granted
63
+ flash[:notice] = "Welcome to the secure area of foo.com!"
64
+ end
65
+
66
+ end
67
+ ```
68
+
69
+ There is also a helper method that can be used in the view or controller. In the view its
70
+ handy for conditional menus or stuff like that.
71
+
72
+ ```erb
73
+ <% restrict_to "(admin | moderator) & !blacklist" do %>
74
+ <%= link_to "Admin & Moderator only link", :action =>'foo' %>
75
+ <% end %>
76
+ ```
77
+
78
+ So the gist of it is that in the `access_control` controller macro, you can assign
79
+ permission logic strings to actions in your controller. You supply a hash of
80
+ `:action => 'permissions string'` pairs. Any action not in the list is left open to
81
+ any user. Any action with a logic string gets evaluated on each request to see if
82
+ the current user has the right role to access the action. The plugin has a small
83
+ recursive descent parser that evaluates the permission logic strings against the
84
+ `current_user.roles`.
85
+
86
+ The way this works is that you have your `User` model and a `Role` model. `User <= habtm => Role`.
87
+ So when an action that is access_control’ed gets requested the permission logic string
88
+ gets evaluated against the `current_user.roles`. So a prerequisite of using this plugin
89
+ is that you add a `Role` model with a `title` attribute that `has_and_belongs_to_many :user`
90
+ models. And you need to have a `current_user` method defined somewhere in your controllers
91
+ or user system. Luckily the `acts_as_authenticated` plugin has the `current_user` defined already.
92
+
93
+ So here is the schema of this application including the `Post` model and the `User` and `Role`
94
+ model plus the habtm join table:
95
+
96
+ ```ruby
97
+ ActiveRecord::Schema.define(:version => 3) do
98
+ create_table "posts", :force => true do |t|
99
+ t.column "title", :string, :limit => 40
100
+ t.column "body", :text
101
+ end
102
+ create_table "roles", :force => true do |t|
103
+ t.column "title", :string
104
+ end
105
+ create_table "roles_users", :id => false, :force => true do |t|
106
+ t.column "role_id", :integer
107
+ t.column "user_id", :integer
108
+ end
109
+ create_table "users", :force => true do |t|
110
+ t.column "login", :string, :limit => 40
111
+ t.column "email", :string, :limit => 100
112
+ t.column "crypted_password", :string, :limit => 40
113
+ t.column "salt", :string, :limit => 40
114
+ t.column "created_at", :datetime
115
+ t.column "updated_at", :datetime
116
+ end
117
+ end
118
+ ```
119
+
120
+ And so thats pretty much it for now. You add the roles to the `Role.title` attribute like admin,
121
+ moderator and blacklist like above. These can be anything you want them to be, roles, groups
122
+ or whatever. Then you can use as many nested parens and logic with `& | !` as you want to
123
+ define your complex permissions for accessing your controller. Make sure that your `access_control`
124
+ gets called after the `login_required` before filter because we assume that you are already
125
+ logged in if you made it this far and then we eval the permissions logic.
126
+
127
+ You will want to define these access_control in each controller that needs specific permissions.
128
+ unless you want to protect the same actions in all controllers, then you can put it in
129
+ `application.rb` but I don't recommend it.
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.pattern = 'test/**/*_test.rb'
6
+ t.verbose = true
7
+ end
8
+
9
+ task :default => :test
10
+
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'acl_system2/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'acl_system2'
8
+ gem.version = ACLSystem2::VERSION
9
+ gem.authors = ['Ezra Zygmuntowicz', 'Fabien Franzen', 'Gareth Rees']
10
+ gem.email = ['gareth@garethrees.co.uk']
11
+ gem.description = %q{An access control gem for Rails. A flexible declarative way of protecting your various controller actions using roles.}
12
+ gem.summary = %q{An access control gem for Rails}
13
+ gem.homepage = 'https://github.com/boxuk/acl_system2'
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ['lib']
19
+
20
+ gem.add_development_dependency 'minitest'
21
+ gem.add_development_dependency 'turn'
22
+ gem.add_development_dependency 'rake'
23
+ end
24
+
@@ -0,0 +1,5 @@
1
+ require "#{ File.dirname(__FILE__) }/acl_system2/version"
2
+ require "#{ File.dirname(__FILE__) }/acl_system2/caboose/logic_parser"
3
+ require "#{ File.dirname(__FILE__) }/acl_system2/caboose/role_handler"
4
+ require "#{ File.dirname(__FILE__) }/acl_system2/caboose/access_control"
5
+
@@ -0,0 +1,112 @@
1
+
2
+ module Caboose
3
+
4
+ module AccessControl
5
+
6
+ def self.included(subject)
7
+ subject.extend(ClassMethods)
8
+ if subject.respond_to? :helper_method
9
+ subject.helper_method(:permit?)
10
+ subject.helper_method(:restrict_to)
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ # access_control [:create, :edit] => 'admin & !blacklist',
16
+ # :update => '(admin | moderator) & !blacklist',
17
+ # :list => '(admin | moderator | user) & !blacklist'
18
+ def access_control(actions={})
19
+ # Add class-wide permission callback to before_filter
20
+ defaults = {}
21
+ if block_given?
22
+ yield defaults
23
+ default_block_given = true
24
+ end
25
+ before_filter do |c|
26
+ c.default_access_context = defaults if default_block_given
27
+ @access = AccessSentry.new(c, actions)
28
+ if @access.allowed?(c.action_name)
29
+ c.send(:permission_granted) if c.respond_to?:permission_granted
30
+ else
31
+ if c.respond_to?:permission_denied
32
+ c.send(:permission_denied)
33
+ else
34
+ c.send(:render, :text => "You have insuffient permissions to access #{c.controller_name}/#{c.action_name}")
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end # ClassMethods
40
+
41
+ # return the active access handler, fallback to RoleHandler
42
+ # implement #retrieve_access_handler to return non-default handler
43
+ def access_handler
44
+ if respond_to?(:retrieve_access_handler)
45
+ @handler ||= retrieve_access_handler
46
+ else
47
+ @handler ||= RoleHandler.new
48
+ end
49
+ end
50
+
51
+ # the current access context; will be created if not setup
52
+ # will add current_user and merge any other elements of context
53
+ def access_context(context = {})
54
+ default_access_context.merge(context)
55
+ end
56
+
57
+ def default_access_context
58
+ @default_access_context ||= {}
59
+ @default_access_context[:user] = send(:current_user) if respond_to?(:current_user)
60
+ @default_access_context
61
+ end
62
+
63
+ def default_access_context=(defaults)
64
+ @default_access_context = defaults
65
+ end
66
+
67
+ def permit?(logicstring, context = {})
68
+ access_handler.process(logicstring, access_context(context))
69
+ end
70
+
71
+ # restrict_to "admin | moderator" do
72
+ # link_to "foo"
73
+ # end
74
+ def restrict_to(logicstring, context = {})
75
+ return false if current_user.nil?
76
+ result = ''
77
+ if permit?(logicstring, context)
78
+ result = yield if block_given?
79
+ end
80
+ result
81
+ end
82
+
83
+ class AccessSentry
84
+
85
+ def initialize(subject, actions={})
86
+ @actions = actions.inject({}) do |auth, current|
87
+ [current.first].flatten.each { |action| auth[action] = current.last }
88
+ auth
89
+ end
90
+ @subject = subject
91
+ end
92
+
93
+ def allowed?(action)
94
+ if @actions.has_key? action.to_sym
95
+ return @subject.access_handler.process(@actions[action.to_sym].dup, @subject.access_context)
96
+ elsif @actions.has_key? :DEFAULT
97
+ return @subject.access_handler.process(@actions[:DEFAULT].dup, @subject.access_context)
98
+ else
99
+ return true
100
+ end
101
+ end
102
+
103
+ end # AccessSentry
104
+
105
+ end # AccessControl
106
+
107
+ end # Caboose
108
+
109
+
110
+
111
+
112
+
@@ -0,0 +1,48 @@
1
+ module Caboose
2
+
3
+ module LogicParser
4
+ # This module holds our recursive descent parser that take a logic string
5
+ # the logic string is tested by the enclosing Handler class' #check method
6
+ # Include this module in your Handler class.
7
+
8
+ # recursively processes an permission string and returns true or false
9
+ def process(logicstring, context)
10
+ # if logicstring contains any parenthasized patterns, call process recursively on them
11
+ while logicstring =~ /\(/
12
+ logicstring.sub!(/\(([^\)]+)\)/) {
13
+ process($1, context)
14
+ }
15
+ end
16
+
17
+ # process each operator in order of precedence
18
+ #!
19
+ while logicstring =~ /!/
20
+ logicstring.sub!(/!([^ &|]+)/) {
21
+ (!check(logicstring[$1], context)).to_s
22
+ }
23
+ end
24
+
25
+ #&
26
+ if logicstring =~ /&/
27
+ return (process(logicstring[/^[^&]+/], context) and process(logicstring[/^[^&]+&(.*)$/,1], context))
28
+ end
29
+
30
+ #|
31
+ if logicstring =~ /\|/
32
+ return (process(logicstring[/^[^\|]+/], context) or process(logicstring[/^[^\|]+\|(.*)$/,1], context))
33
+ end
34
+
35
+ # constants
36
+ if logicstring =~ /^\s*true\s*$/i
37
+ return true
38
+ elsif logicstring =~ /^\s*false\s*$/i
39
+ return false
40
+ end
41
+
42
+ # single list items
43
+ (check(logicstring.strip, context))
44
+ end
45
+
46
+ end # LogicParser
47
+
48
+ end
@@ -0,0 +1,20 @@
1
+ module Caboose
2
+
3
+ class AccessHandler
4
+ include LogicParser
5
+
6
+ def check(key, context)
7
+ false
8
+ end
9
+
10
+ end
11
+
12
+ class RoleHandler < AccessHandler
13
+
14
+ def check(key, context)
15
+ context[:user].roles.map{ |role| role.title.downcase}.include? key.downcase
16
+ end
17
+
18
+ end # End RoleHandler
19
+
20
+ end
@@ -0,0 +1,3 @@
1
+ module ACLSystem2
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,5 @@
1
+ require "#{ File.dirname(__FILE__) }/../lib/acl_system2"
2
+
3
+ ActionController::Base.send :include, Caboose
4
+ ActionController::Base.send :include, Caboose::AccessControl
5
+
@@ -0,0 +1,162 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/test_helper'
3
+ require 'ostruct'
4
+
5
+ # mock objects
6
+
7
+ class User
8
+
9
+ attr_accessor :name
10
+
11
+ def name
12
+ @name ||= 'anon'
13
+ @name
14
+ end
15
+
16
+ def roles
17
+ [OpenStruct.new(:title => 'admin'), OpenStruct.new(:title => 'user')]
18
+ end
19
+
20
+ end
21
+
22
+ class ControllerProxy
23
+
24
+ attr_accessor :action_name
25
+
26
+ class << self
27
+
28
+ attr_reader :before_block
29
+
30
+ def before_filter(&block)
31
+ @before_block = block if block_given?
32
+ end
33
+
34
+ end
35
+
36
+ def before_action
37
+ self.class.before_block.call(self)
38
+ end
39
+
40
+ include Caboose::AccessControl
41
+
42
+ access_control([:create, :edit] => 'admin & !blacklist',
43
+ :update => '(admin | moderator) & !blacklist',
44
+ :list => '(admin | moderator | user) & !blacklist',
45
+ :private => 'vip') do |context|
46
+ context[:variable] = 'value'
47
+ context[:login_time] = Time.new
48
+ end
49
+
50
+ def permission_granted
51
+ true
52
+ end
53
+
54
+ def permission_denied
55
+ false
56
+ end
57
+
58
+ def current_user
59
+ User.new
60
+ end
61
+
62
+ end
63
+
64
+ class FabOnlyHandler < Caboose::AccessHandler
65
+
66
+ def check(key, context)
67
+ (context[:user].name.downcase == 'fabien' and context[:user].roles.map{ |role| role.title.downcase}.include?(key))
68
+ end
69
+
70
+ end
71
+
72
+ class ControllerProxyWithFabHandler < ControllerProxy
73
+
74
+ def retrieve_access_handler
75
+ FabOnlyHandler.new
76
+ end
77
+
78
+ end
79
+
80
+
81
+ # tests
82
+ class AccessControlTest < Test::Unit::TestCase
83
+
84
+
85
+ def test_first
86
+ context = { :user => User.new }
87
+ @handler = Caboose::RoleHandler.new
88
+ assert @handler.process("(admin | moderator) & !blacklist", context)
89
+ assert @handler.process("(user | moderator) & !blacklist", context)
90
+ assert @handler.process("(user | moderator | user) & !blacklist", context)
91
+ assert @handler.process("(user | moderator | !blacklist)", context)
92
+ assert @handler.process("user & !blacklist", context)
93
+ assert @handler.process("!moderator & !blacklist", context)
94
+ assert @handler.process("admin & user & !blacklist", context)
95
+ assert_equal @handler.process("moderator | blacklist", context), false
96
+ assert_equal @handler.process("!admin | blacklist", context), false
97
+ assert_equal @handler.process("moderator | unknown", context), false
98
+ assert_equal @handler.process("!anon & !moderator", context), true
99
+ end
100
+
101
+ def test_custom_access_handler
102
+ context = { :user => User.new }
103
+ controller = ControllerProxyWithFabHandler.new
104
+ assert_equal controller.permit?("(admin | moderator) & !blacklist", context), false
105
+
106
+ context[:user].name = 'Ezra'
107
+ assert_equal controller.permit?("(admin | moderator) & !blacklist", context), false
108
+
109
+ context[:user].name = 'Fabien'
110
+ assert controller.permit?("(admin | moderator) & !blacklist", context)
111
+ end
112
+
113
+ def test_permit
114
+ context = { :user => User.new }
115
+ controller = ControllerProxy.new
116
+ assert controller.permit?("(admin | moderator) & !blacklist", context)
117
+ assert controller.permit?("(user | moderator) & !blacklist", context)
118
+ assert controller.permit?("(user | moderator | user) & !blacklist", context)
119
+ assert controller.permit?("(user | moderator | !blacklist)", context)
120
+ assert controller.permit?("user & !blacklist", context)
121
+ assert controller.permit?("!moderator & !blacklist", context)
122
+ assert controller.permit?("admin & user & !blacklist", context)
123
+ assert_equal controller.permit?("moderator | blacklist", context), false
124
+ assert_equal controller.permit?("!admin | blacklist", context), false
125
+ assert_equal controller.permit?("moderator", context), false
126
+ assert_equal controller.permit?("!anon & !moderator", context), true
127
+ end
128
+
129
+ def test_restrict_to
130
+ controller = ControllerProxy.new
131
+ assert_block do
132
+ controller.restrict_to "admin | moderator" do
133
+ true
134
+ end
135
+ end
136
+ end
137
+
138
+ def test_before_filter
139
+ context = { :user => User.new }
140
+ controller = ControllerProxy.new
141
+
142
+ controller.action_name = 'list'
143
+ assert_block { controller.before_action }
144
+
145
+ controller.action_name = 'other'
146
+ assert_block { controller.before_action }
147
+
148
+ controller.action_name = 'private'
149
+ assert_block { !controller.before_action }
150
+ end
151
+
152
+ def test_set_default_context_with_block
153
+ context = { :user => User.new }
154
+ controller = ControllerProxy.new
155
+ controller.action_name = 'list'
156
+ controller.before_action
157
+ assert controller.access_context.include?(:user)
158
+ assert controller.access_context.include?(:variable)
159
+ assert controller.access_context.include?(:login_time)
160
+ end
161
+
162
+ end
@@ -0,0 +1,8 @@
1
+ require 'turn'
2
+
3
+ Turn.config do |c|
4
+ c.format = :dot
5
+ end
6
+
7
+ require "#{ File.dirname(__FILE__) }/../lib/acl_system2"
8
+
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acl_system2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Ezra Zygmuntowicz
14
+ - Fabien Franzen
15
+ - Gareth Rees
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2013-01-29 00:00:00 Z
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: minitest
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: turn
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rake
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :development
63
+ version_requirements: *id003
64
+ description: An access control gem for Rails. A flexible declarative way of protecting your various controller actions using roles.
65
+ email:
66
+ - gareth@garethrees.co.uk
67
+ executables: []
68
+
69
+ extensions: []
70
+
71
+ extra_rdoc_files: []
72
+
73
+ files:
74
+ - .gitignore
75
+ - Gemfile
76
+ - LICENSE.txt
77
+ - README.md
78
+ - Rakefile
79
+ - acl_system2.gemspec
80
+ - lib/acl_system2.rb
81
+ - lib/acl_system2/caboose/access_control.rb
82
+ - lib/acl_system2/caboose/logic_parser.rb
83
+ - lib/acl_system2/caboose/role_handler.rb
84
+ - lib/acl_system2/version.rb
85
+ - rails/init.rb
86
+ - test/access_control_test.rb
87
+ - test/test_helper.rb
88
+ homepage: https://github.com/boxuk/acl_system2
89
+ licenses: []
90
+
91
+ post_install_message:
92
+ rdoc_options: []
93
+
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ hash: 3
111
+ segments:
112
+ - 0
113
+ version: "0"
114
+ requirements: []
115
+
116
+ rubyforge_project:
117
+ rubygems_version: 1.8.23
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: An access control gem for Rails
121
+ test_files:
122
+ - test/access_control_test.rb
123
+ - test/test_helper.rb