Polar 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.
- data/.gitignore +36 -0
- data/Polar.gemspec +56 -0
- data/README.md +61 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/polar.rb +23 -0
- data/lib/polar/adapter.rb +7 -0
- data/lib/polar/adapters/active_record.rb +86 -0
- data/lib/polar/errors.rb +7 -0
- data/lib/polar/frameworks/rails.rb +55 -0
- data/lib/polar/groups.rb +71 -0
- data/lib/polar/permissions.rb +101 -0
- data/spec/polar_spec.rb +54 -0
- data/spec/spec_helper.rb +94 -0
- metadata +83 -0
data/.gitignore
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
## MAC OS
|
|
2
|
+
.DS_Store
|
|
3
|
+
|
|
4
|
+
## TEXTMATE
|
|
5
|
+
*.tmproj
|
|
6
|
+
tmtags
|
|
7
|
+
|
|
8
|
+
## EMACS
|
|
9
|
+
*~
|
|
10
|
+
\#*
|
|
11
|
+
.\#*
|
|
12
|
+
|
|
13
|
+
## VIM
|
|
14
|
+
*.swp
|
|
15
|
+
|
|
16
|
+
## Rubinius
|
|
17
|
+
*.rbc
|
|
18
|
+
|
|
19
|
+
## PROJECT::GENERAL
|
|
20
|
+
*.gem
|
|
21
|
+
coverage
|
|
22
|
+
rdoc
|
|
23
|
+
pkg
|
|
24
|
+
tmp
|
|
25
|
+
doc
|
|
26
|
+
log
|
|
27
|
+
.yardoc
|
|
28
|
+
measurements
|
|
29
|
+
|
|
30
|
+
## BUNDLER
|
|
31
|
+
.bundle
|
|
32
|
+
Gemfile.local
|
|
33
|
+
Gemfile.lock
|
|
34
|
+
|
|
35
|
+
## PROJECT::SPECIFIC
|
|
36
|
+
vendor
|
data/Polar.gemspec
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Generated by jeweler
|
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
|
4
|
+
# -*- encoding: utf-8 -*-
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = %q{Polar}
|
|
8
|
+
s.version = "0.2.0"
|
|
9
|
+
|
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
|
+
s.authors = ["Grzegorz Kazulak", "Lukasz Tackowiak"]
|
|
12
|
+
s.date = %q{2010-07-29}
|
|
13
|
+
s.description = %q{Control access like a bear}
|
|
14
|
+
s.email = %q{grzegorz.kazulak@gmail.com}
|
|
15
|
+
s.extra_rdoc_files = [
|
|
16
|
+
"README.md"
|
|
17
|
+
]
|
|
18
|
+
s.files = [
|
|
19
|
+
".gitignore",
|
|
20
|
+
"Polar.gemspec",
|
|
21
|
+
"README.md",
|
|
22
|
+
"Rakefile",
|
|
23
|
+
"VERSION",
|
|
24
|
+
"init.rb",
|
|
25
|
+
"lib/polar.rb",
|
|
26
|
+
"lib/polar/adapter.rb",
|
|
27
|
+
"lib/polar/adapters/active_record.rb",
|
|
28
|
+
"lib/polar/errors.rb",
|
|
29
|
+
"lib/polar/frameworks/rails.rb",
|
|
30
|
+
"lib/polar/groups.rb",
|
|
31
|
+
"lib/polar/permissions.rb",
|
|
32
|
+
"spec/polar_spec.rb",
|
|
33
|
+
"spec/spec_helper.rb"
|
|
34
|
+
]
|
|
35
|
+
s.homepage = %q{http://github.com/grzegorzkazulak/Polar}
|
|
36
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
37
|
+
s.require_paths = ["lib"]
|
|
38
|
+
s.rubyforge_project = %q{grizzlies}
|
|
39
|
+
s.rubygems_version = %q{1.3.7}
|
|
40
|
+
s.summary = %q{Access control for polar bears}
|
|
41
|
+
s.test_files = [
|
|
42
|
+
"spec/polar_spec.rb",
|
|
43
|
+
"spec/spec_helper.rb"
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
if s.respond_to? :specification_version then
|
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
48
|
+
s.specification_version = 3
|
|
49
|
+
|
|
50
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
51
|
+
else
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Polar
|
|
2
|
+
===============================
|
|
3
|
+
|
|
4
|
+
Polar is a simple, fast and powerful way to manage user permissions/groups. It uses redis as a backend storage mechanism for all your permissions mechanism and simple DSL to define all the available permissions within a system.
|
|
5
|
+
|
|
6
|
+
Usage example
|
|
7
|
+
----------
|
|
8
|
+
|
|
9
|
+
class User < ActiveRecord::Base
|
|
10
|
+
|
|
11
|
+
default :permissions do |p|
|
|
12
|
+
p.edit_profile
|
|
13
|
+
p.manage_addresses
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
default :groups do |g|
|
|
17
|
+
g.administrators
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Below the code definition to accompany the settings from User model. That should resist somewhere in your initializers folder.
|
|
22
|
+
|
|
23
|
+
Example definition
|
|
24
|
+
----------
|
|
25
|
+
|
|
26
|
+
Polar.define :permissions do |gz|
|
|
27
|
+
gz.edit_profile do |c|
|
|
28
|
+
c.allow :users_controller, :only => [:edit, :update]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
gz.manage_addresses do |gz|
|
|
32
|
+
c.allow :addresses_controller
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Example usage
|
|
37
|
+
----------
|
|
38
|
+
|
|
39
|
+
@user = User.first
|
|
40
|
+
|
|
41
|
+
# Check if user has specific permission
|
|
42
|
+
@user.can?(:edit_profile)
|
|
43
|
+
|
|
44
|
+
# Check if user belongs to specific group
|
|
45
|
+
@user.member_of?(:administrators)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## Note on Patches/Pull Requests
|
|
49
|
+
|
|
50
|
+
* Fork the project.
|
|
51
|
+
* Make your feature addition or bug fix.
|
|
52
|
+
* Add tests for it. This is important so I don't break it in a
|
|
53
|
+
future version unintentionally.
|
|
54
|
+
* Commit, do not mess with rakefile, version, or history.
|
|
55
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
|
56
|
+
* Send me a pull request. Bonus points for topic branches.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### Credits
|
|
60
|
+
|
|
61
|
+
- Grzegorz Kazulak <grzegorz.kazulak@gmail.com>
|
data/Rakefile
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'rake'
|
|
2
|
+
require 'spec/rake/spectask'
|
|
3
|
+
adapters = Dir[File.dirname(__FILE__) + '/lib/polar/adapter/*.rb'].map{|file| File.basename(file, '.rb') }
|
|
4
|
+
|
|
5
|
+
task :spec do
|
|
6
|
+
adapters.map{|adapter| "spec:#{adapter}"}.each do |spec|
|
|
7
|
+
Rake::Task[spec].invoke
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
namespace :spec do
|
|
12
|
+
adapters.each do |adapter|
|
|
13
|
+
Spec::Rake::SpecTask.new(adapter) do |spec|
|
|
14
|
+
spec.spec_files = FileList['spec/*_spec.rb']
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
|
20
|
+
spec.libs << 'lib' << 'spec'
|
|
21
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
|
22
|
+
spec.rcov = true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
task :default => :spec
|
|
26
|
+
|
|
27
|
+
begin
|
|
28
|
+
gem 'jeweler', '~> 1.4'
|
|
29
|
+
require 'jeweler'
|
|
30
|
+
|
|
31
|
+
Jeweler::Tasks.new do |gem|
|
|
32
|
+
gem.name = 'Polar'
|
|
33
|
+
gem.summary = 'Access control for polar bears'
|
|
34
|
+
gem.description = 'Control access like a bear'
|
|
35
|
+
gem.email = 'grzegorz.kazulak@gmail.com'
|
|
36
|
+
gem.homepage = 'http://github.com/grzegorzkazulak/%s' % gem.name
|
|
37
|
+
gem.authors = [ 'Grzegorz Kazulak', 'Lukasz Tackowiak']
|
|
38
|
+
|
|
39
|
+
gem.rubyforge_project = 'grizzlies'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
Jeweler::GemcutterTasks.new
|
|
43
|
+
|
|
44
|
+
FileList['tasks/**/*.rake'].each { |task| import task }
|
|
45
|
+
rescue LoadError
|
|
46
|
+
puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
task(:spec) {} # stub out the spec task for as long as we don't have any specs
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.2.0
|
data/init.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'polar'
|
data/lib/polar.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
require 'polar/adapter'
|
|
3
|
+
require 'polar/errors'
|
|
4
|
+
require 'polar/groups'
|
|
5
|
+
require 'polar/permissions'
|
|
6
|
+
require 'polar/frameworks/rails'
|
|
7
|
+
|
|
8
|
+
module Polar
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
attr_accessor :logger
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.define(type)
|
|
15
|
+
case type
|
|
16
|
+
when :permissions
|
|
17
|
+
yield(Polar::Permissions.define)
|
|
18
|
+
when :groups
|
|
19
|
+
yield(Polar::Groups.define)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
self.logger = Logger.new(STDOUT)
|
|
23
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
|
|
3
|
+
class UserPermission < ActiveRecord::Base;
|
|
4
|
+
def self.get_for_subject(subject_id)
|
|
5
|
+
find_all_by_user_id(subject_id)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class UserGroup < ActiveRecord::Base;
|
|
10
|
+
def self.get_for_subject(subject_id)
|
|
11
|
+
find_all_by_user_id(subject_id)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module Polar #nodoc
|
|
16
|
+
module ActiveRecordExtensions
|
|
17
|
+
|
|
18
|
+
def self.included(base)
|
|
19
|
+
base.extend(ClassMethods)
|
|
20
|
+
base.send(:include, InstanceMethods)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module InstanceMethods
|
|
24
|
+
def permission_object
|
|
25
|
+
UserPermission
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def group_object
|
|
29
|
+
UserGroup
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def permissions
|
|
33
|
+
return @permissions if defined?(@permissions)
|
|
34
|
+
auth = Polar::Permissions.new
|
|
35
|
+
auth.fill_subject_from_external_store(self.id, permission_object, group_object)
|
|
36
|
+
@permissions = auth.subject_store.sort { |a,b| a.to_s <=> b.to_s }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def groups
|
|
40
|
+
return @groups if defined?(@groups)
|
|
41
|
+
auth = Polar::Groups.new
|
|
42
|
+
auth.fill_subject_from_external_store(self.id, group_object)
|
|
43
|
+
@groups = auth.subject_store.sort { |a,b| a.to_s <=> b.to_s }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Check whenever specific subject has right permission assigned to him
|
|
47
|
+
# either via defaults defined in the model or the database
|
|
48
|
+
def can?(permission)
|
|
49
|
+
raise Polar::PermissionNotDefined unless Polar::Permissions.defined_store.has_key?(permission)
|
|
50
|
+
permissions.include? permission
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Check whenever specific subject is a member of a right group
|
|
54
|
+
# either via defaults defined in the model or the database
|
|
55
|
+
def member_of?(group)
|
|
56
|
+
groups.include? group
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
module ClassMethods
|
|
62
|
+
|
|
63
|
+
def acts_as_polar
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def owner(authorization_subject)
|
|
67
|
+
# Return owner
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def default(kind)
|
|
71
|
+
case kind
|
|
72
|
+
when :permissions
|
|
73
|
+
# Permissions
|
|
74
|
+
yield(Polar::DefaultPermissions.instance)
|
|
75
|
+
when :groups
|
|
76
|
+
# Groups
|
|
77
|
+
yield(Polar::DefaultGroups.instance)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if defined? ActiveRecord::Base
|
|
85
|
+
ActiveRecord::Base.send(:include, Polar::ActiveRecordExtensions)
|
|
86
|
+
end
|
data/lib/polar/errors.rb
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
module Polar #nodoc
|
|
2
|
+
class PermissionNotDefinedButSetAsDefault < StandardError; end
|
|
3
|
+
class PermissionNotDefined < StandardError; end
|
|
4
|
+
class AuthorizationFailureNoUser < StandardError; end
|
|
5
|
+
class AuthorizationFailureDenyPermission < StandardError; end
|
|
6
|
+
class AuthorizationFailureMissedPermission < StandardError; end
|
|
7
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'action_controller'
|
|
2
|
+
|
|
3
|
+
module Polar #nodoc
|
|
4
|
+
module ActionControllerExtensions
|
|
5
|
+
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
base.send(:include, InstanceMethods)
|
|
9
|
+
base.class_eval do
|
|
10
|
+
before_filter "authorized?"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module InstanceMethods
|
|
15
|
+
def authorized?
|
|
16
|
+
begin
|
|
17
|
+
name = "#{controller_path.gsub('/', '__')}_controller".to_sym
|
|
18
|
+
if Polar::Permissions.for_controller.has_key?(name)
|
|
19
|
+
perm_info = Polar::Permissions.for_controller[name]
|
|
20
|
+
action = perm_info.has_key?(action_name.to_sym) ? action_name.to_sym : :all
|
|
21
|
+
user = current_user
|
|
22
|
+
if perm_info[:action].present?
|
|
23
|
+
perm_info[action][:deny].each do |deny_perm|
|
|
24
|
+
raise Polar::AuthorizationFailureNoUser if user.nil?
|
|
25
|
+
raise Polar::AuthorizationFailureDenyPermission if user.can?(deny_perm)
|
|
26
|
+
end
|
|
27
|
+
perm_info[action][:allow].each do |allow_perm|
|
|
28
|
+
raise Polar::AuthorizationFailureNoUser if user.nil?
|
|
29
|
+
raise Polar::AuthorizationFailureMissedPermission unless user.can?(allow_perm)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
rescue Polar::AuthorizationFailureNoUser
|
|
34
|
+
logger.debug "=> No valid User found"
|
|
35
|
+
redirect_to root_path
|
|
36
|
+
rescue Polar::AuthorizationFailureDenyPermission
|
|
37
|
+
logger.debug "=> User #{current_user.id} has :deny permission on this action"
|
|
38
|
+
redirect_to root_path
|
|
39
|
+
rescue Polar::AuthorizationFailureMissedPermission
|
|
40
|
+
logger.debug "=> Authorization Failure :: User #{current_user.id} doesn't have required permissions"
|
|
41
|
+
redirect_to root_path
|
|
42
|
+
end
|
|
43
|
+
return true
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
module ClassMethods
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if defined? ActionController::Base
|
|
54
|
+
ActionController::Base.send(:include, Polar::ActionControllerExtensions)
|
|
55
|
+
end
|
data/lib/polar/groups.rb
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Polar #nodoc
|
|
2
|
+
class DefaultGroups
|
|
3
|
+
|
|
4
|
+
# This method is executed whenever a default group is defined
|
|
5
|
+
# in subject's model
|
|
6
|
+
def method_missing(method, *params)
|
|
7
|
+
Groups.instance.subject_store << method
|
|
8
|
+
self
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Protects from creating more than one instance of this class
|
|
12
|
+
def self.instance
|
|
13
|
+
@__instance__ ||= new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class Groups
|
|
19
|
+
attr_accessor :defined_groups_store
|
|
20
|
+
attr_accessor :subject_store
|
|
21
|
+
|
|
22
|
+
def initialize(instance_object = false)
|
|
23
|
+
@defined_groups_store ||= []
|
|
24
|
+
@subject_store ||= []
|
|
25
|
+
unless instance_object
|
|
26
|
+
@defined_groups_store = self.class.instance.defined_groups_store.clone
|
|
27
|
+
@subject_store = self.class.instance.subject_store.clone
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.instance
|
|
34
|
+
@__instance__ ||= new(true)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.define(&block)
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.method_missing(method, &block)
|
|
42
|
+
yield GroupHash.new(method) if block_given?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.defined_store
|
|
46
|
+
@defined_groups_store ||= {}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def fill_subject_from_external_store(subject_id, storage)
|
|
50
|
+
storage.get_for_subject(subject_id).each do |group|
|
|
51
|
+
self.subject_store << group.group_name.to_sym
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class GroupHash < Hash
|
|
57
|
+
|
|
58
|
+
def initialize(method)
|
|
59
|
+
self[:group_name] = method.to_sym
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def have(*params)
|
|
63
|
+
self[:params] = params
|
|
64
|
+
Polar::Groups.defined_store[self[:group_name]] = self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def deny(*params)
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
module Polar #nodoc
|
|
2
|
+
class DefaultPermissions
|
|
3
|
+
|
|
4
|
+
# This method is executed whenever a default permission is defined
|
|
5
|
+
# in subject's model
|
|
6
|
+
def method_missing(method, *params)
|
|
7
|
+
Permissions.instance.subject_store << method.to_sym
|
|
8
|
+
self
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Protects from creating more than one instance of this class
|
|
12
|
+
def self.instance
|
|
13
|
+
@__instance__ ||= new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class Permissions
|
|
19
|
+
attr_accessor :defined_permissions_store
|
|
20
|
+
attr_accessor :subject_store
|
|
21
|
+
attr_accessor :permissions_for_controller
|
|
22
|
+
|
|
23
|
+
def initialize(instance_object = false)
|
|
24
|
+
@defined_permissions_store ||= []
|
|
25
|
+
@subject_store ||= []
|
|
26
|
+
unless instance_object
|
|
27
|
+
@defined_permissions_store = self.class.instance.defined_permissions_store.clone
|
|
28
|
+
@subject_store = self.class.instance.subject_store.clone
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.instance
|
|
35
|
+
@__instance__ ||= new(true)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.define(&block)
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.method_missing(method, &block)
|
|
43
|
+
yield PermissionHash.new(method) if block_given?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.defined_store
|
|
47
|
+
@defined_permissions_store ||= {}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.for_controller
|
|
51
|
+
@permissions_for_controller ||= {}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.add_for_controller(perm_hash)
|
|
55
|
+
controller = perm_hash[:object].to_sym
|
|
56
|
+
actions = perm_hash[:params].present? && perm_hash[:params].has_key?(:only) ? perm_hash[:params][:only] : [:all]
|
|
57
|
+
for_controller[controller] ||= {}
|
|
58
|
+
actions.each do |action|
|
|
59
|
+
for_controller[controller][action] ||= {:allow => [], :deny => []}
|
|
60
|
+
for_controller[controller][action][perm_hash[:access_type]] << perm_hash[:permission_name]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def fill_subject_from_external_store(subject_id, perm_storage, group_storage)
|
|
65
|
+
perm_storage.get_for_subject(subject_id).each do |perm|
|
|
66
|
+
self.subject_store << perm.permission_name.to_sym
|
|
67
|
+
end
|
|
68
|
+
groups = Polar::Groups.new
|
|
69
|
+
groups.fill_subject_from_external_store(subject_id, group_storage)
|
|
70
|
+
groups.subject_store.each do |group|
|
|
71
|
+
if Polar::Groups.defined_store.has_key?(group.to_sym)
|
|
72
|
+
self.subject_store.concat(Polar::Groups.defined_store[group.to_sym][:params])
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class PermissionHash < Hash
|
|
79
|
+
|
|
80
|
+
def initialize(method)
|
|
81
|
+
self[:permission_name] = method.to_sym
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def allow(*params)
|
|
85
|
+
add(:allow, params)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def deny(*params)
|
|
89
|
+
add(:deny, params)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def add(perm_type, params)
|
|
93
|
+
self[:access_type] = perm_type
|
|
94
|
+
self[:object] = params.shift
|
|
95
|
+
self[:params] = params.first
|
|
96
|
+
Polar::Permissions.add_for_controller(self)
|
|
97
|
+
Polar::Permissions.defined_store[self[:permission_name]] ||= []
|
|
98
|
+
Polar::Permissions.defined_store[self[:permission_name]] << self
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
data/spec/polar_spec.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
|
|
3
|
+
describe Polar do
|
|
4
|
+
before do
|
|
5
|
+
@user = User.create
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "should respond to default" do
|
|
9
|
+
User.should respond_to(:default)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should respond to owner" do
|
|
13
|
+
User.should respond_to(:owner)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should return default permissions for user" do
|
|
17
|
+
@user.permissions
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should check if user is a member of specific group" do
|
|
21
|
+
@user.member_of?(:clients).should be(true)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should return true if user is a member of a group stored in database" do
|
|
25
|
+
UserGroup.create(:user_id => @user.id, :group_name => "test_group")
|
|
26
|
+
UserGroup.create(:user_id => @user.id, :group_name => "another_group")
|
|
27
|
+
@user.member_of?(:test_group).should be(true)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should check and return false if user is NOT a member of specific group" do
|
|
31
|
+
@user.member_of?(:not_existing_group).should be(false)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should check if user has specific permission" do
|
|
35
|
+
@user.can?(:edit_profile).should be(true)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should return false for permission NOT assigned for specific, even in database" do
|
|
39
|
+
@user.can?(:add_addresses).should be(false)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should return true for permission assigned for specific user in database" do
|
|
43
|
+
UserPermission.create(:user_id => @user.id, :permission_name => "add_addresses")
|
|
44
|
+
@user.can?(:add_addresses).should be(true)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should return false if user DO NOT have specific permission" do
|
|
48
|
+
lambda {
|
|
49
|
+
@user.can?(:do_something_that_doesnt_exist)
|
|
50
|
+
}.should raise_error(Polar::PermissionNotDefined)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
3
|
+
|
|
4
|
+
require 'rubygems'
|
|
5
|
+
require 'polar'
|
|
6
|
+
require 'spec'
|
|
7
|
+
require 'spec/autorun'
|
|
8
|
+
require 'active_record'
|
|
9
|
+
|
|
10
|
+
Spec::Runner.configure do |config|
|
|
11
|
+
#EMPTY
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
##########################################################################
|
|
16
|
+
# Active Record connection
|
|
17
|
+
##########################################################################
|
|
18
|
+
|
|
19
|
+
begin
|
|
20
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
|
21
|
+
rescue ArgumentError
|
|
22
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
##########################################################################
|
|
27
|
+
# Database schema
|
|
28
|
+
##########################################################################
|
|
29
|
+
|
|
30
|
+
ActiveRecord::Base.configurations = true
|
|
31
|
+
ActiveRecord::Schema.define(:version => 1) do
|
|
32
|
+
create_table :users do |t|
|
|
33
|
+
t.string :name
|
|
34
|
+
t.datetime :created_at
|
|
35
|
+
t.datetime :updated_at
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
create_table :user_permissions do |t|
|
|
39
|
+
t.integer :user_id
|
|
40
|
+
t.string :permission_name
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
create_table :user_groups do |t|
|
|
44
|
+
t.integer :user_id
|
|
45
|
+
t.string :group_name
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
create_table :groups do |t|
|
|
49
|
+
t.string :group_name
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
create_table :permission_groups do |t|
|
|
53
|
+
t.string :permission_name
|
|
54
|
+
t.integer :group_id
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##########################################################################
|
|
60
|
+
# Define permissions
|
|
61
|
+
##########################################################################
|
|
62
|
+
|
|
63
|
+
Polar.define :permissions do |gp|
|
|
64
|
+
gp.edit_profile do |c|
|
|
65
|
+
c.allow :users_controller, :only => [:edit, :update]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
gp.add_addresses do |c|
|
|
69
|
+
c.allow :addresses_controller, :only => [:new, :create]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
##########################################################################
|
|
74
|
+
# Define groups
|
|
75
|
+
##########################################################################
|
|
76
|
+
|
|
77
|
+
Polar.define :groups do |gg|
|
|
78
|
+
gg.administrators do |a|
|
|
79
|
+
a.have :add_addresses, :edit_profile
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
gg.clients do |c|
|
|
83
|
+
c.have :edit_profile
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class User < ActiveRecord::Base
|
|
88
|
+
include Polar::ActiveRecordExtensions
|
|
89
|
+
acts_as_polar
|
|
90
|
+
|
|
91
|
+
default :groups do |g|
|
|
92
|
+
g.clients
|
|
93
|
+
end
|
|
94
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: Polar
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 23
|
|
5
|
+
prerelease: false
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 2
|
|
9
|
+
- 0
|
|
10
|
+
version: 0.2.0
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- Grzegorz Kazulak
|
|
14
|
+
- Lukasz Tackowiak
|
|
15
|
+
autorequire:
|
|
16
|
+
bindir: bin
|
|
17
|
+
cert_chain: []
|
|
18
|
+
|
|
19
|
+
date: 2010-07-29 00:00:00 +02:00
|
|
20
|
+
default_executable:
|
|
21
|
+
dependencies: []
|
|
22
|
+
|
|
23
|
+
description: Control access like a bear
|
|
24
|
+
email: grzegorz.kazulak@gmail.com
|
|
25
|
+
executables: []
|
|
26
|
+
|
|
27
|
+
extensions: []
|
|
28
|
+
|
|
29
|
+
extra_rdoc_files:
|
|
30
|
+
- README.md
|
|
31
|
+
files:
|
|
32
|
+
- .gitignore
|
|
33
|
+
- Polar.gemspec
|
|
34
|
+
- README.md
|
|
35
|
+
- Rakefile
|
|
36
|
+
- VERSION
|
|
37
|
+
- init.rb
|
|
38
|
+
- lib/polar.rb
|
|
39
|
+
- lib/polar/adapter.rb
|
|
40
|
+
- lib/polar/adapters/active_record.rb
|
|
41
|
+
- lib/polar/errors.rb
|
|
42
|
+
- lib/polar/frameworks/rails.rb
|
|
43
|
+
- lib/polar/groups.rb
|
|
44
|
+
- lib/polar/permissions.rb
|
|
45
|
+
- spec/polar_spec.rb
|
|
46
|
+
- spec/spec_helper.rb
|
|
47
|
+
has_rdoc: true
|
|
48
|
+
homepage: http://github.com/grzegorzkazulak/Polar
|
|
49
|
+
licenses: []
|
|
50
|
+
|
|
51
|
+
post_install_message:
|
|
52
|
+
rdoc_options:
|
|
53
|
+
- --charset=UTF-8
|
|
54
|
+
require_paths:
|
|
55
|
+
- lib
|
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
hash: 3
|
|
62
|
+
segments:
|
|
63
|
+
- 0
|
|
64
|
+
version: "0"
|
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
|
+
none: false
|
|
67
|
+
requirements:
|
|
68
|
+
- - ">="
|
|
69
|
+
- !ruby/object:Gem::Version
|
|
70
|
+
hash: 3
|
|
71
|
+
segments:
|
|
72
|
+
- 0
|
|
73
|
+
version: "0"
|
|
74
|
+
requirements: []
|
|
75
|
+
|
|
76
|
+
rubyforge_project: grizzlies
|
|
77
|
+
rubygems_version: 1.3.7
|
|
78
|
+
signing_key:
|
|
79
|
+
specification_version: 3
|
|
80
|
+
summary: Access control for polar bears
|
|
81
|
+
test_files:
|
|
82
|
+
- spec/polar_spec.rb
|
|
83
|
+
- spec/spec_helper.rb
|