Skip to content

Commit

Permalink
Up to 0.0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
dzaporozhets committed Aug 17, 2011
1 parent e21880c commit d1ed92f
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 69 deletions.
48 changes: 35 additions & 13 deletions README.markdown
@@ -1,4 +1,4 @@
## Six - is a authorization gem for ruby!
## Six - is a ultra simple authorization gem for ruby!

### Installation

Expand All @@ -12,13 +12,14 @@
class BookRules
# All authorization works on objects with method 'allowed'
# No magic behind the scene
# You can put this method to any class you want
# It should always return array
# You can put this method to any class or object you want
# It should always return array
# And be aready to get nil in args
def self.allowed(author, book)
rules = []

# good practice is to check for object type
return rules unless book.instance_of?(Book)
return rules unless book && book.instance_of?(Book)

rules << :read_book if book.published?
rules << :edit_book if author && author.id == book.author_id
Expand All @@ -31,7 +32,7 @@ class BookRules
end

# Add rules to namespace ':book' & global namespace
Six.add_pack(:book, BookRules)
Six.add_pack(:book, BookRules) # true

Six.allowed? :read_book, nil, nil # false
Six.allowed? :read_book, nil, published_book # true
Expand Down Expand Up @@ -80,7 +81,7 @@ class Book < ActiveRecord::Base

def self.allowed(object, subject)
rules = []
return rules unless book.instance_of?(Book)
return rules unless book && book.instance_of?(Book)
rules << :read_book if subject.public?
rules << :edit_book if object && object.id == subject.author_id
rules
Expand Down Expand Up @@ -115,19 +116,40 @@ class CarRules
end
end

Six.add_pack(:book, BookRules)
Six.add_pack(:car, CarRules)
# add packs
Six.add_pack(:book, BookRules) # true
Six.add_pack(:car, CarRules) # true
Six.add_pack(:ufo, nil) # false
Six.add_pack!(:ufo, nil) # raise Six::InvalidPackPassed

Six.use(:book).allowed? :read_book, nil, nil # true
Six.use(:car).allowed? :drive, nil, nil # true

Six.use(:car).allowed? :read_book, nil, nil # false
Six.use(:book).allowed? :drive, nil, nil # false
# use specific pack for rules
Six.use(:book) # true
Six.allowed? :read_book, nil, nil # true
Six.allowed? :drive, nil, nil # false

Six.use(:car)
Six.allowed? :drive, nil, nil # true
Six.allowed? :read_book, nil, nil # false

# use reset to return to global usage
Six.reset_use
Six.allowed? :drive, nil, nil # true
Six.allowed? :drive, nil, nil # true
Six.allowed? :read_book, nil, nil # true

# different use methods
Six.use(:ufo) # false
Six.use!(:ufo) # raise Six::NoPackError


# remove pack
Six.remove(:book) # true
Six.remove(:ufo) # false
Six.remove!(:ufo) # raise Six::NoPackError

Six.use(:car) # true
Six.current_rule_pack # :car

```


Expand Down
120 changes: 113 additions & 7 deletions lib/six.rb
@@ -1,4 +1,16 @@
class Six
class NoPackError < StandardError
def message
"No such pack"
end
end

class InvalidPackPassed < StandardError
def message
"Wrong Rule Pack. You must provide correct 'allowed' method"
end
end

class << self
attr_accessor :rules_packs
attr_accessor :current_rule_pack
Expand All @@ -7,42 +19,136 @@ def rules_packs
@rules_packs ||= {}
end

# Set current pack from stored packs by key
#
# == Parameters:
# name::
# A Symbol declaring the key name of stored pack
#
# == Returns:
# self or false
#
def use(name)
@current_rule_pack = rules_packs[name.to_sym] if pack_exist?(name)
self
if pack_exist?(name)
@current_rule_pack = name.to_sym
self
end
end

# Same as use but raise exception if no pack found
def use!(name)
use(name) ? self : raise_no_such_pack
end

# Add pack to authorization class
#
# == Parameters:
# name::
# A Symbol declaring the key name of stored pack
# pack::
# Any kind of object responding to allowed method
#
# == Returns:
# true or false
#
def add_pack(name, pack)
rules_packs[name.to_sym] = pack if valid_rules_object?(pack)
end

# Same as add_pack but raise exception if pack is invalid
def add_pack!(name, pack)
add_pack(name, pack) || raise_incorrect_pack_object
end

# Remove pack from authorization class
#
# == Parameters:
# name::
# A Symbol declaring the key name of stored pack
#
# == Returns:
# true or false
#
def remove_pack(name)
if pack_exist?(name)
@current_rule_pack = nil if rules_packs[name.to_sym] == @current_rule_pack
rules_packs.delete(name.to_sym)
end
end

# Same as remove_pack but raise exception if pack wasnt found
def remove_pack!(name)
remove_pack(name) || raise_no_such_pack
end

# Check if object for rule pack is valid
#
# == Parameters:
# pack::
# Any kind of object responding to allowed method
#
# == Returns:
# true or false
#
def valid_rules_object?(object)
object.respond_to?(:allowed) ||
raise("Wrong Rule Pack. You must provide 'allowed' method")
object.respond_to?(:allowed) &&
object.send(:allowed, nil, nil).kind_of?(Array)
rescue
false
end

# Check if authorization class has pack with such name
#
# == Parameters:
# name::
# A Symbol declaring the key name of stored pack
#
# == Returns:
# true or false
#
def pack_exist?(name)
rules_packs.has_key?(name.to_sym) ||
raise("No such pack")
rules_packs.has_key?(name.to_sym)
end

# Check if authorization class allow access for object to subject
# using selected pack or all stored.
# Basically this method
# 1. send :allowed for every stored object in packs and pass object & subject
# 2. check if any of results include allowed action
#
# == Parameters:
# action::
# Action name to check for access
# object::
# object trying to access resource
# subject::
# resource
#
# == Returns:
# true or false
#
def allowed?(action, object, subject)
if current_rule_pack
current_rule_pack.allowed(object, subject).include?(action)
rules_packs[current_rule_pack].allowed(object, subject).include?(action)
else
rules_packs.values.map { |rp| rp.allowed(object, subject) }.flatten.include?(action)
end
end

# Reset current used rule pack so auth class use
# global allowed? for new request
def reset_use
@current_rule_pack = nil
end

protected

def raise_no_such_pack
raise Six::NoPackError.new
end

def raise_incorrect_pack_object
raise Six::InvalidPackPassed.new
end
end
end
4 changes: 2 additions & 2 deletions six.gemspec
@@ -1,7 +1,7 @@
Gem::Specification.new do |s|
s.name = 'six'
s.version = '0.0.2'
s.date = '2011-08-13'
s.version = '0.0.3'
s.date = '2011-08-17'
s.summary = "six"
s.description = "Very simple authorization gem"
s.authors = ["Dmitriy Zaporozhets"]
Expand Down
100 changes: 67 additions & 33 deletions spec/six_rules_packs_spec.rb
Expand Up @@ -3,58 +3,92 @@

describe Six do
describe "Rules Packs" do
class MyRules
def allowed(object, subject)
[]
end
let(:rules) { BookRules.new }

describe :add_pack do
it { Six.add_pack(:global, rules).should be_true }
it { Six.add_pack(:wrong, nil).should be_false }
end

describe :add_pack! do
it { Six.add_pack!(:global, rules).should be_true }
it { lambda { Six.add_pack!(:wrong, nil)}.should raise_error(Six::InvalidPackPassed) }
end

describe "namespace usage" do
before do
@rules = MyRules.new
@guard = Six
@guard.add_pack(:global, @rules)
end

describe "namespace(pack) usage" do
before { Six.add_pack(:global, rules) }

describe :use do
before do
@guard.use(:global)
before { Six.use(:global) }

it "should return class object itself when use existing pack" do
Six.use(:global).should == Six
end

describe "should set current role pack with selected" do
it { Six.current_rule_pack.should == :global }
end

it { @guard.current_rule_pack.should_not be_nil }
it { lambda { @guard.use(:noname)}.should raise_error("No such pack") }
it "should return false when trying to use unexisting pack" do
Six.use(:noname).should be_false
end
end

describe :reset_use do
before do
@guard.use(:global)
@guard.reset_use
describe :use! do
it "should not raise error if trying to use existing pack" do
lambda { Six.use!(:global)}.should_not raise_error
end

it { @guard.current_rule_pack.should be_nil }
it "should raise error if trying to use unexisting pack" do
lambda { Six.use!(:noname)}.should raise_error(Six::NoPackError)
end
end
end


describe :add_pack do
describe :reset_use do
before do
@rules = MyRules.new
@guard = Six
Six.use(:global)
Six.reset_use
end

it { @guard.add_pack(:global, @rules).should be_true }
it { lambda { @guard.add_pack(:wrong, nil)}.should raise_error("Wrong Rule Pack. You must provide 'allowed' method") }
it "should set current rule pack variable as nil" do
Six.current_rule_pack.should be_nil
end
end

describe :remove_pack do
before do
@rules = MyRules.new
@guard = Six
@guard.add_pack(:global, @rules)
context "removing pack" do
before { Six.add_pack(:global, rules) }

describe :remove_pack do
it { Six.remove_pack(:global).should be_true }
it { Six.remove_pack(:zzz).should be_false }
end

describe :remove_pack! do
it { Six.remove_pack!(:global).should be_true }
it { lambda { Six.remove_pack!(:zzz)}.should raise_error(Six::NoPackError) }
end
end

describe :valid_rules_object? do
let (:invalid_with_allowed) do
Class.new { def allowed; nil; end }.new
end

let (:invalid_wo_allowed) do
Object.new
end

it { @guard.remove_pack(:global).should be_true }
it { lambda { @guard.remove_pack(:zzz)}.should raise_error("No such pack") }
it { Six.valid_rules_object?(BookRules.new).should be_true }
it { Six.valid_rules_object?(invalid_with_allowed).should be_false }
it { Six.valid_rules_object?(invalid_wo_allowed).should be_false }
end

describe :pack_exist? do
before { Six.add_pack(:global, rules) }

it { Six.pack_exist?(:global).should be_true }
it { Six.pack_exist?(:ufo).should be_false }
end
end
end

0 comments on commit d1ed92f

Please sign in to comment.