Skip to content

Commit

Permalink
support for permission attached to groups + validation in rails contr…
Browse files Browse the repository at this point in the history
…ollers
  • Loading branch information
grzegorzkazulak committed Jul 29, 2010
1 parent 9417cf3 commit 0c29a99
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 66 deletions.
22 changes: 21 additions & 1 deletion grizzly.gemspec
Expand Up @@ -9,18 +9,38 @@ Gem::Specification.new do |s|

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Grzegorz Kazulak"]
s.date = %q{2010-07-19}
s.date = %q{2010-07-20}
s.description = %q{Control access like a Bear}
s.email = %q{grzegorz.kazulak@gmail.com}
s.extra_rdoc_files = [
"README.md"
]
s.files = [
".gitignore",
"README.md",
"Rakefile",
"VERSION",
"grizzly.gemspec",
"init.rb",
"lib/grizzly.rb",
"lib/grizzly/adapter.rb",
"lib/grizzly/adapters/active_record.rb",
"lib/grizzly/errors.rb",
"lib/grizzly/groups.rb",
"lib/grizzly/permissions.rb",
"spec/grizzly_spec.rb",
"spec/spec_helper.rb"
]
s.homepage = %q{http://github.com/grzegorzkazulak/grizzly/grizzly}
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{grizzly}
s.rubygems_version = %q{1.3.7}
s.summary = %q{ACL for bears}
s.test_files = [
"spec/grizzly_spec.rb",
"spec/spec_helper.rb"
]

if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
Expand Down
2 changes: 1 addition & 1 deletion init.rb
@@ -1 +1 @@
require File.dirname(__FILE__) + "/lib/grizzly"
require 'grizzly'
14 changes: 6 additions & 8 deletions lib/grizzly.rb
@@ -1,14 +1,12 @@
require File.expand_path(File.dirname(__FILE__) + '/grizzly/adapter')
require 'logger'
require 'grizzly/adapter'
require 'grizzly/errors'
require 'grizzly/groups'
require 'grizzly/permissions'
require 'grizzly/frameworks/rails'

module Grizzly

autoload :Permissions, 'grizzly/permissions'
autoload :Groups, 'grizzly/groups'

autoload :PermissionNotDefinedButSetAsDefault, 'grizzly/errors'
autoload :PermissionNotDefined, 'grizzly/errors'


class << self
attr_accessor :logger
end
Expand Down
52 changes: 31 additions & 21 deletions lib/grizzly/adapters/active_record.rb
@@ -1,7 +1,16 @@
require 'active_record'

class UserPermission < ActiveRecord::Base; end
class UserGroup < ActiveRecord::Base; end
class UserPermission < ActiveRecord::Base;
def self.get_for_subject(subject_id)
find_all_by_user_id(subject_id)
end
end

class UserGroup < ActiveRecord::Base;
def self.get_for_subject(subject_id)
find_all_by_user_id(subject_id)
end
end

module Grizzly #nodoc
module ActiveRecordExtensions
Expand All @@ -12,38 +21,39 @@ def self.included(base)
end

module InstanceMethods
def permission_object
UserPermission
end

def group_object
UserGroup
end

def permissions
::UserPermission.find_all_by_user_id(self.id)
return @permissions if defined?(@permissions)
auth = Grizzly::Permissions.new
auth.fill_subject_from_external_store(self.id, permission_object, group_object)
@permissions = auth.subject_store.sort { |a,b| a.to_s <=> b.to_s }
end

def permissions
::UserGroup.find_all_by_user_id(self.id)
def groups
return @groups if defined?(@groups)
auth = Grizzly::Groups.new
auth.fill_subject_from_external_store(self.id, group_object)
@groups = auth.subject_store.sort { |a,b| a.to_s <=> b.to_s }
end

# Check whenever specific subject has right permission assigned to him
# either via defaults defined in the model or the database
def can?(permission)
check(permission, Grizzly::Permissions, ::UserPermission)
raise Grizzly::PermissionNotDefined unless Grizzly::Permissions.defined_store.has_key?(permission)
permissions.include? permission
end

# Check whenever specific subject is a member of a right group
# either via defaults defined in the model or the database
def member_of?(group)
check(group, Grizzly::Groups, ::UserGroup)
end

protected

def check(group, type, storage)
unless type.instance.subject_store.include? group
storage.find_all_by_user_id(self.id).each do |sg|
type.instance.subject_store << sg.group_name.to_sym
end
return true if type.instance.subject_store.include? group
else
return true
end
false
groups.include? group
end

end
Expand Down
3 changes: 3 additions & 0 deletions lib/grizzly/errors.rb
@@ -1,4 +1,7 @@
module Grizzly #nodoc
class PermissionNotDefinedButSetAsDefault < StandardError; end
class PermissionNotDefined < StandardError; end
class AuthorizationFailureNoUser < StandardError; end
class AuthorizationFailureDenyPermission < StandardError; end
class AuthorizationFailureMissedPermission < StandardError; end
end
55 changes: 55 additions & 0 deletions lib/grizzly/frameworks/rails.rb
@@ -0,0 +1,55 @@
require 'action_controller'

module Grizzly #nodoc
module ActionControllerExtensions

def self.included(base)
base.extend(ClassMethods)
base.send(:include, InstanceMethods)
base.class_eval do
before_filter "authorized?"
end
end

module InstanceMethods
def authorized?
begin
name = "#{controller_path.gsub('/', '__')}_controller".to_sym
if Grizzly::Permissions.for_controller.has_key?(name)
perm_info = Grizzly::Permissions.for_controller[name]
action = perm_info.has_key?(action_name.to_sym) ? action_name.to_sym : :all
user = current_user
if perm_info[:action].present?
perm_info[action][:deny].each do |deny_perm|
raise Grizzly::AuthorizationFailureNoUser if user.nil?
raise Grizzly::AuthorizationFailureDenyPermission if user.can?(deny_perm)
end
perm_info[action][:allow].each do |allow_perm|
raise Grizzly::AuthorizationFailureNoUser if user.nil?
raise Grizzly::AuthorizationFailureMissedPermission unless user.can?(allow_perm)
end
end
end
rescue Grizzly::AuthorizationFailureNoUser
logger.debug "GRIZZLY makes WRRRRRRRRRRAU! => Authorization Failure :: No valid User found"
redirect_to root_path
rescue Grizzly::AuthorizationFailureDenyPermission
logger.debug "GRIZZLY makes WRRRRRRRRRRAU! => Authorization Failure :: User #{current_user.id} has deny permission"
redirect_to root_path
rescue Grizzly::AuthorizationFailureMissedPermission
logger.debug "GRIZZLY makes WRRRRRRRRRRAU! => Authorization Failure :: User #{current_user.id} hasn't got required permission"
redirect_to root_path
end
return true
end
end

module ClassMethods

end
end
end

if defined? ActionController::Base
ActionController::Base.send(:include, Grizzly::ActionControllerExtensions)
end
25 changes: 14 additions & 11 deletions lib/grizzly/groups.rb
Expand Up @@ -19,19 +19,19 @@ class Groups
attr_accessor :defined_groups_store
attr_accessor :subject_store

def initialize
unless @defined_groups_store
@defined_groups_store = []
end

unless @subject_store
@subject_store = []
def initialize(instance_object = false)
@defined_groups_store ||= []
@subject_store ||= []
unless instance_object
@defined_groups_store = self.class.instance.defined_groups_store.clone
@subject_store = self.class.instance.subject_store.clone
end

self
end

def self.instance
@__instance__ ||= new
@__instance__ ||= new(true)
end

def self.define(&block)
Expand All @@ -43,10 +43,13 @@ def self.method_missing(method, &block)
end

def self.defined_store
unless @defined_groups_store
@defined_groups_store = {}
@defined_groups_store ||= {}
end

def fill_subject_from_external_store(subject_id, storage)
storage.get_for_subject(subject_id).each do |group|
self.subject_store << group.group_name.to_sym
end
@defined_groups_store
end
end

Expand Down
66 changes: 49 additions & 17 deletions lib/grizzly/permissions.rb
Expand Up @@ -18,20 +18,21 @@ def self.instance
class Permissions
attr_accessor :defined_permissions_store
attr_accessor :subject_store
def initialize
unless @defined_permissions_store
@defined_permissions_store = []
end

unless @subject_store
@subject_store = []
attr_accessor :permissions_for_controller

def initialize(instance_object = false)
@defined_permissions_store ||= []
@subject_store ||= []
unless instance_object
@defined_permissions_store = self.class.instance.defined_permissions_store.clone
@subject_store = self.class.instance.subject_store.clone
end

self
end

def self.instance
@__instance__ ||= new
@__instance__ ||= new(true)
end

def self.define(&block)
Expand All @@ -43,11 +44,35 @@ def self.method_missing(method, &block)
end

def self.defined_store
unless @defined_permissions_store
@defined_permissions_store = {}
@defined_permissions_store ||= {}
end

def self.for_controller
@permissions_for_controller ||= {}
end

def self.add_for_controller(perm_hash)
controller = perm_hash[:object].to_sym
actions = perm_hash[:params].present? && perm_hash[:params].has_key?(:only) ? perm_hash[:params][:only] : [:all]
for_controller[controller] ||= {}
actions.each do |action|
for_controller[controller][action] ||= {:allow => [], :deny => []}
for_controller[controller][action][perm_hash[:access_type]] << perm_hash[:permission_name]
end
@defined_permissions_store
end
end

def fill_subject_from_external_store(subject_id, perm_storage, group_storage)
perm_storage.get_for_subject(subject_id).each do |perm|
self.subject_store << perm.permission_name.to_sym
end
groups = Grizzly::Groups.new
groups.fill_subject_from_external_store(subject_id, group_storage)
groups.subject_store.each do |group|
if Grizzly::Groups.defined_store.has_key?(group.to_sym)
self.subject_store.concat(Grizzly::Groups.defined_store[group.to_sym][:params])
end
end
end
end

class PermissionHash < Hash
Expand All @@ -57,13 +82,20 @@ def initialize(method)
end

def allow(*params)
self[:access_type] = :allow
self[:params] = params
Grizzly::Permissions.defined_store[self[:permission_name]] = self[:params]
add(:allow, params)
end

def deny(*params)

add(:deny, params)
end

def add(perm_type, params)
self[:access_type] = perm_type
self[:object] = params.shift
self[:params] = params.first
Grizzly::Permissions.add_for_controller(self)
Grizzly::Permissions.defined_store[self[:permission_name]] ||= []
Grizzly::Permissions.defined_store[self[:permission_name]] << self
end
end
end
4 changes: 2 additions & 2 deletions spec/grizzly_spec.rb
Expand Up @@ -18,7 +18,7 @@
end

it "should check if user is a member of specific group" do
@user.member_of?(:administrators).should be(true)
@user.member_of?(:clients).should be(true)
end

it "should return true if user is a member of a group stored in database" do
Expand All @@ -32,7 +32,7 @@
end

it "should check if user has specific permission" do
@user.can?(:edit_profile).should be(true)
@user.can?(:edit_profile).should be(true)
end

it "should return false for permission NOT assigned for specific, even in database" do
Expand Down
11 changes: 6 additions & 5 deletions spec/spec_helper.rb
Expand Up @@ -45,8 +45,13 @@
t.string :group_name
end

create_table :groups do |t|
t.string :group_name
end

create_table :permission_groups do |t|
t.string :permission_name
t.integer :group_id
end

end
Expand Down Expand Up @@ -83,11 +88,7 @@ class User < ActiveRecord::Base
include Grizzly::ActiveRecordExtensions
acts_as_grizzly

default :permissions do |p|
p.add_addresses
end

default :groups do |g|
g.administrators
g.clients
end
end

0 comments on commit 0c29a99

Please sign in to comment.