Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/aclatraz.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module Aclatraz

# Initialize Aclatraz system with given datastore.
#
# Aclatraz.init :redis, "redis://localhost:6379/0"
# Aclatraz.init :redis, :host => "127.0.0.1", :database => 0
# Aclatraz.init :tokyocabinet, "./permissions.tch"
# Aclatraz.init MyCustomDatastore, :option => 1 # ...
def self.init(store, *args)
Expand Down
6 changes: 6 additions & 0 deletions lib/aclatraz/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,11 @@ def pack(role, object=nil)
end
data.join("/")
end

# Resolve the given class name to a Class object
def resolve_class(name)
name.split('::').inject(Kernel) {|scope, const_name| scope.const_get(const_name)}
end

end # Helpers
end # Aclatraz
28 changes: 28 additions & 0 deletions lib/aclatraz/store/redis.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,34 @@ def roles(suspect=nil)
end
end

def permissions(for_role, suspect, object=nil)
given_klass = (object.nil? || object.is_a?(Class)) ? object : object.class

permissions = @backend.smembers(SUSPECT_ROLES_KEY % suspect_id(suspect)).map { |role|
role = unpack(role)
if role.size > 1 && role[0] == for_role
if 3 == role.size
klass = resolve_class(role[1])
if (given_klass.nil? || klass == given_klass)
[klass, role[2]] # return the object id
else
nil
end
else
klass = resolve_class(role[1])
if (given_klass.nil? || klass == given_klass)
klass # return the class
else
nil
end
end
else
nil
end
}
permissions.compact.uniq
end

def check(role, suspect, object=nil)
@backend.sismember(SUSPECT_ROLES_KEY % suspect_id(suspect), pack(role.to_s, object)) or
object && !object.is_a?(Class) ? check(role, suspect, object.class) : false
Expand Down
42 changes: 42 additions & 0 deletions lib/aclatraz/suspect.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,48 @@ def all
Aclatraz.store.roles(suspect)
end
alias_method :list, :all

# Clears all roles assigned to the current object and returns the list.
#
# ==== Examples
#
# suspect.roles.assign(:foo)
# suspect.roles.assign(:bar)
# suspect.roles.clear # => ["foo", "bar"]
# suspect.roles.has?(:foo) # => false
# suspect.roles.has?(:bar) # => false
def clear
all.each do |role|
delete(role)
end
end
alias_method :delete_all, :clear
alias_method :remove_all, :clear

# Enumerates all objects on which explicit permissions for the given role
# have been granted via suspect.roles.add(:role, object)
#
# This method does not return the objects that permissions were granted for to avoid
# costly single retrieval of potentially hundreds of objects from a store. Instead a
# tupel of [Class, Id] is returned for each individual object permissions were granted
# on and the Class is returned if permissions were granted on a Class.
#
# You can enumerate permissions granted on a type of objects by passing the Class or
# one instance of the Class as second parameter
#
# ==== Examples
#
# suspect.roles.assign(:author, Page.find(15))
# suspect.roles.assign(:author, BlogEntry.find(15))
# suspect.roles.assign(:author, Book)
# suspect.roles.permissions(:author) => [[Page, 15], [BlogEntry, 15], Book]
# suspect.roles.permissions(:author, Page) # => [[Page, 15]]
# suspect.roles.permissions(:author, Page.find(1)) # => [[Page, 15]]
#
def permissions(role, object=nil)
Aclatraz.store.permissions(role, suspect, object)
end

end # Roles

class SemanticRoles
Expand Down
2 changes: 1 addition & 1 deletion spec/aclatraz/acl_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

describe "Aclatraz ACL" do
subject { Aclatraz::ACL }
before(:all) { Aclatraz.init(:redis, "redis://localhost:6379/0") }
before(:all) {Aclatraz.init :redis, :host => "127.0.0.1", :database => 0 }

it "should properly set suspect" do
acl = subject.new(:suspect) {}
Expand Down
2 changes: 1 addition & 1 deletion spec/aclatraz/guard_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
describe "Aclatraz guard" do
subject { Class.new(StubGuarded) }
let(:suspect) { @suspect ||= StubSuspect.new }
before(:all) { Aclatraz.init(:redis, "redis://localhost:6379/0") }
before(:all) { Aclatraz.init :redis, :host => "127.0.0.1", :database => 0 }
define_method(:deny_access) { raise_error(Aclatraz::AccessDenied) }

it "#acl_guard? should be true" do
Expand Down
4 changes: 2 additions & 2 deletions spec/aclatraz/stores_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@
let(:target) { StubTarget.new }

context "for Redis store", :store => 'redis' do
subject { Aclatraz.init(:redis, "redis://localhost:6379/0") }
subject { Aclatraz.init :redis, :host => "127.0.0.1", :database => 0 }

it_should_behave_like :store do
it "should respect persistent connection given on initalize" do
Aclatraz.instance_variable_set("@store", nil)
Aclatraz.init(:redis, Redis.new("redis://localhost:6379/0"))
Aclatraz.init :redis, :host => "127.0.0.1", :database => 0
Aclatraz.store.instance_variable_get('@backend').should be_kind_of(Redis)
Aclatraz.store.instance_variable_get('@backend').ping.should be_true
end
Expand Down
12 changes: 11 additions & 1 deletion spec/aclatraz/suspect_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require File.dirname(__FILE__) + '/../spec_helper'

describe "Aclatraz suspect" do
before(:all) { Aclatraz.init(:redis, "redis://localhost:6379/0") }
before(:all) { Aclatraz.init :redis, :host => "127.0.0.1", :database => 0 }
subject { StubSuspect.new }
let(:target) { StubTarget.new }

Expand All @@ -27,6 +27,11 @@
end

it "should allow to get list of roles assigned to user" do
subject.roles.clear
subject.roles.assign(:first)
subject.roles.assign(:second, StubTarget)
subject.roles.assign(:third, target)

(subject.roles.all - ["first", "second", "third"]) .should be_empty
end

Expand All @@ -40,6 +45,11 @@
subject.roles.has?(:third, target).should be_false
end

it "should properly clear all given permissions" do
subject.roles.clear
subject.roles.all.should be_empty
end

context "syntactic sugars" do
it "should properly set given role" do
subject.is.first!
Expand Down