permission_policy 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c8ea6d2e2a7840711423115ac405faa69f1f4e1f
4
- data.tar.gz: 1537caf4e3d92a1a32710e9e6bc895f68a7becce
3
+ metadata.gz: e282b311b9a97875e9918d7fe57f6c1c19150d81
4
+ data.tar.gz: 24241e62b1a2355be883b2d3edec11f141c2d250
5
5
  SHA512:
6
- metadata.gz: dc15add153228915f7260aaf366db7363a8aeb033b1e4df5ed6bf6717b074e533f127988e5f08098502364ae3846dcf79c433c68a5e29489b0a772058dbd5e7c
7
- data.tar.gz: d00d2c74aa4effd92e9b9851af5f616ea6996b216f975693f01d0a8673317f248cd65cbae7398a140e78662f5419dab7b5146d19e54a564605dbdefa23ab5766
6
+ metadata.gz: 7049c534d01ebaa7e4472c57e6a12dd56973d9eb4d22d3e2c18da977adde0472ce1a09c9d0516b353b0d7b50ef6e9ba9e6cd1c1ab97485880609cc5cb358b4aa
7
+ data.tar.gz: b7b4be9758970112f4c462aee6328ddecc667e7d7d99430976c5f4bdedf9fe1a510bddb415e25620b6ac636a293d17899c5fdb43cf9f3f00e9464a04fefb0b80
data/.rubocop.yml ADDED
@@ -0,0 +1,56 @@
1
+ AllCops:
2
+ Exclude:
3
+ - '**/Rakefile'
4
+ - '**/Gemfile'
5
+ - '**/Guardfile'
6
+ - 'spec/**/*'
7
+
8
+ Metrics/LineLength:
9
+ Max: 120 # this is already a lot
10
+
11
+ Lint/AssignmentInCondition:
12
+ Enabled: false # it can be a nice shortcut
13
+
14
+ Style/Documentation:
15
+ Enabled: false # atm we don't need this
16
+
17
+ Style/DoubleNegation:
18
+ Enabled: false # the double !! are great for explicitly return true or false
19
+
20
+ Style/SignalException:
21
+ Enabled: false # prefer raise over fail
22
+
23
+ Style/AndOr:
24
+ Enabled: false # for controlflow 'and' & 'or' are great
25
+ # but yes they can be tricky because of their operational precendence:
26
+ # http://ruby-doc.org/core-2.0/doc/syntax/precedence_rdoc.html
27
+
28
+ Metrics/CyclomaticComplexity:
29
+ # count of the number of linearly independent paths
30
+ Max: 4 # don't go ever higher than 5, because then it makes no sense at all.
31
+ # for a tradeoff you can disable it locally in a section of a file with:
32
+ # rubocop:disable Metrics/CyclomaticComplexity
33
+
34
+ Metrics/PerceivedComplexity:
35
+ # the perceived complexity is often higher than the cyclomatic complexity
36
+ Max: 5 # the optimal value can be different for each developer depending on the experience
37
+ # for a tradeoff you can disable it locally in a section of a file with:
38
+ # rubocop:disable Metrics/PerceivedComplexity
39
+
40
+ Metrics/MethodLength:
41
+ Max: 10 # this is already a lot, but for some controller actions a big if/else is more readable
42
+
43
+ Style/GuardClause:
44
+ Enabled: false # usually this blows up the line over the maximum line length
45
+
46
+ Style/WordArray:
47
+ Enabled: false # sometimes not as readable as plain string array
48
+
49
+ Style/TrailingComma:
50
+ Enabled: false # we think it's good practice, because of cleaner git diffs
51
+
52
+ Style/RegexpLiteral:
53
+ Enabled: false # we like %r{} a lot
54
+
55
+ Style/RaiseArgs:
56
+ Enabled: false # don't agree
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard :rspec, cmd: 'bundle exec rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { 'spec' }
4
+ watch('spec/spec_helper.rb') { 'spec' }
5
+ end
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
5
7
 
6
- task default: :spec
8
+ task default: [:spec, :rubocop]
@@ -0,0 +1,50 @@
1
+ module PermissionPolicy
2
+ class Authorization
3
+ attr_reader :preconditions
4
+
5
+ def initialize(context)
6
+ @preconditions = []
7
+
8
+ PermissionPolicy.preconditions.each do |precondition|
9
+ set! precondition, context.public_send(precondition)
10
+ @preconditions << precondition
11
+ end
12
+ end
13
+
14
+ # Decides if the action is allowed based on the matching strategy.
15
+ # You may want to use this method for controlflow inside views.
16
+ #
17
+ # Example:
18
+ #
19
+ # do_something if allowed?(:manage, subject: my_subject)
20
+ #
21
+ def allowed?(action, options = {})
22
+ strategy_for(action, options).allowed?
23
+ end
24
+
25
+ # Delegates to #allowed? but raises a NotAllowed exception when false.
26
+ # You may want to use this method for halting the execution of a controller method.
27
+ #
28
+ # Example:
29
+ #
30
+ # def edit
31
+ # allow!(:manage, subject: my_subject)
32
+ # end
33
+ #
34
+ def authorize!(action, options = {})
35
+ !!allowed?(action, options) or raise PermissionPolicy::NotAllowed
36
+ end
37
+
38
+ private
39
+
40
+ # Finds the matching strategy which can decide if the action is allowed by lazy checking
41
+ def strategy_for(*args)
42
+ PermissionPolicy.strategies.lazy.map { |klass| Strategies.const_get(klass).new(self, *args) }.find(&:match?)
43
+ end
44
+
45
+ def set!(var, value)
46
+ self.class.send(:attr_reader, var)
47
+ instance_variable_set(:"@#{var}", value) or raise PermissionPolicy::MissingPrecondition.new(var)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,30 @@
1
+ module PermissionPolicy
2
+ class Configuration < OpenStruct
3
+ def preconditions
4
+ precondition_attributes || [:current_user]
5
+ end
6
+
7
+ def strategies
8
+ strategy_order || [:UnknownStrategy]
9
+ end
10
+ end
11
+
12
+ class << self
13
+ attr_accessor :configuration
14
+
15
+ extend Forwardable
16
+ delegate [:preconditions, :strategies] => :config
17
+
18
+ def configure
19
+ yield(config)
20
+ end
21
+
22
+ def config
23
+ self.configuration ||= Configuration.new
24
+ end
25
+
26
+ def authorize_with(*args)
27
+ configure { |c| c.precondition_attributes = *args }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_support/concern'
2
+
3
+ module PermissionPolicy
4
+ module ControllerAdditions
5
+ module ClassMethods
6
+ def authorize_with(*args)
7
+ PermissionPolicy.authorize_with(*args)
8
+ end
9
+ end
10
+
11
+ module InstanceMethods
12
+ extend ActiveSupport::Concern
13
+
14
+ included do
15
+ helper_method :allowed?
16
+ delegate :allowed?, to: :permission_policy
17
+ delegate :authorize!, to: :permission_policy
18
+ end
19
+
20
+ def permission_policy
21
+ @permission_policy ||= PermissionPolicy::Authorization.new(self)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ module PermissionPolicy
2
+ class MissingPrecondition < StandardError
3
+ attr_reader :precondition
4
+
5
+ def initialize(precondition)
6
+ @precondition = precondition
7
+ end
8
+
9
+ def message
10
+ "missing precondition: #{precondition}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ module PermissionPolicy
2
+ class NotAllowed < StandardError
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ module PermissionPolicy
2
+ class Railtie < ::Rails::Railtie
3
+ initializer 'permission_policy.configure_controller' do
4
+ ActiveSupport.on_load :action_controller do
5
+ include PermissionPolicy::ControllerAdditions::InstanceMethods
6
+ extend PermissionPolicy::ControllerAdditions::ClassMethods
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,44 @@
1
+ module PermissionPolicy
2
+ module Strategies
3
+ #
4
+ # The base strategy defines the object API for all strategies which can be
5
+ # used for permission checks. Each strategy should inherit from it and
6
+ # implement #match? and #allowed?
7
+ #
8
+ class BaseStrategy
9
+ # attributes which are available for #match? and #allowed?
10
+ # are passed from the authorization class.
11
+ #
12
+ # precondition_attributes:: for example [:current_user]
13
+ # action:: This will be :view or :manage
14
+ # options:: A hash having :subject or :feature as keys
15
+ attr_accessor :action, :options
16
+
17
+ def initialize(authorization, action = nil, options = {})
18
+ authorization.preconditions.each do |attribute|
19
+ self.class.send(:attr_accessor, attribute)
20
+ instance_variable_set(:"@#{attribute}", authorization.public_send(attribute))
21
+ end
22
+
23
+ self.action = action
24
+ self.options = options
25
+ end
26
+
27
+ # Check if the strategy is responsible for handling the permission check
28
+ # Has to return true or false
29
+ def match?
30
+ raise NotImplementedError, 'please implement #match? '\
31
+ "for #{self.class.name} which should return true or false, "\
32
+ 'depending on if it can decide #allowed?'
33
+ end
34
+
35
+ # Check if user has necessary permission
36
+ # Has to return true or false
37
+ def allowed?
38
+ raise NotImplementedError, 'please implement #allowed? '\
39
+ "for #{self.class.name} which should decide if the action is allowed, "\
40
+ 'based on the given attributes'
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ module PermissionPolicy
2
+ module Strategies
3
+ # Fallback strategy if no other matches. It allways matches and always
4
+ # denies access no matter what.
5
+ class UnknownStrategy < BaseStrategy
6
+ def match?
7
+ true
8
+ end
9
+
10
+ def allowed?
11
+ false
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module PermissionPolicy
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
@@ -1,4 +1,16 @@
1
- require "permission_policy/version"
1
+ require 'ostruct'
2
+ require 'permission_policy/version'
3
+ require 'permission_policy/configuration'
4
+ require 'permission_policy/railtie' if defined?(Rails)
5
+ require 'permission_policy/controller_additions'
2
6
 
3
7
  module PermissionPolicy
8
+ autoload :Authorization, 'permission_policy/authorization'
9
+ autoload :MissingPrecondition, 'permission_policy/errors/missing_precondition'
10
+ autoload :NotAllowed, 'permission_policy/errors/not_allowed'
11
+
12
+ module Strategies
13
+ autoload :BaseStrategy, 'permission_policy/strategies/base_strategy'
14
+ autoload :UnknownStrategy, 'permission_policy/strategies/unknown_strategy'
15
+ end
4
16
  end
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = PermissionPolicy::VERSION
9
9
  spec.authors = ['Marco Schaden', 'Maximilian Schulz']
10
10
  spec.email = ['marco@railslove.com', 'max@railslove.com']
11
- spec.summary = %q{Without order, there is chaos}
12
- spec.description = %q{Expandable object oriented authorization solution for Ruby/Rails applications}
11
+ spec.summary = 'Without order, there is chaos'
12
+ spec.description = 'Expandable object oriented authorization solution for Ruby/Rails applications'
13
13
  spec.homepage = ''
14
14
  spec.license = 'MIT'
15
15
 
@@ -18,10 +18,13 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency 'activesupport', '>= 3.0.0'
21
+ spec.add_dependency 'activesupport', '>= 4.0.0'
22
22
 
23
23
  spec.add_development_dependency 'bundler', '~> 1.6'
24
24
  spec.add_development_dependency 'rspec', '~> 3.0.0'
25
+ spec.add_development_dependency 'guard-rspec'
25
26
  spec.add_development_dependency 'rake'
26
27
  spec.add_development_dependency 'pry'
28
+ spec.add_development_dependency 'rubocop'
29
+ spec.add_development_dependency 'actionpack', '>= 4.0.0'
27
30
  end
@@ -0,0 +1,30 @@
1
+ module PermissionPolicy
2
+ RSpec.describe 'Authorization' do
3
+ before do
4
+ PermissionPolicy.authorize_with :my_user, :my_account
5
+ end
6
+
7
+ subject { PermissionPolicy::Authorization.new(context) }
8
+
9
+ context 'valid' do
10
+ let(:context) { double('context', my_user: 'foo', my_account: 'bar') }
11
+
12
+ it 'sets attribute readers for each precondition' do
13
+ expect(subject.my_user).to eq('foo')
14
+ expect(subject.my_account).to eq('bar')
15
+ end
16
+
17
+ it 'remembers precondition attributes' do
18
+ expect(subject.preconditions).to eq([:my_user, :my_account])
19
+ end
20
+ end
21
+
22
+ context 'invalid' do
23
+ let(:context) { double('context', my_user: nil, my_account: nil) }
24
+
25
+ it 'raises missing precondition error' do
26
+ expect { subject }.to raise_error('missing precondition: my_user')
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ module PermissionPolicy
2
+ RSpec.describe Configuration do
3
+ before { PermissionPolicy.configuration = nil }
4
+
5
+ it 'has a default precondition' do
6
+ expect(subject.preconditions).to eq([:current_user])
7
+ end
8
+
9
+ it 'has a default strategy' do
10
+ expect(subject.strategies).to eq([:UnknownStrategy])
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,42 @@
1
+ require 'action_controller'
2
+
3
+ class MetalTestController < ActionController::Metal
4
+ include AbstractController::Helpers
5
+ include PermissionPolicy::ControllerAdditions::InstanceMethods
6
+ extend PermissionPolicy::ControllerAdditions::ClassMethods
7
+
8
+ def foo
9
+ end
10
+
11
+ def bar
12
+ end
13
+ end
14
+
15
+
16
+ module PermissionPolicy
17
+ RSpec.describe 'ControllerAdditions' do
18
+ subject { MetalTestController.new }
19
+
20
+ context 'authorization' do
21
+ before do
22
+ MetalTestController.authorize_with :foo, :bar
23
+ is_expected.to receive(:foo) { 'foo' }
24
+ is_expected.to receive(:bar) { 'bar' }
25
+ end
26
+
27
+ it 'is available throuth #permission_policy' do
28
+ expect(subject.permission_policy).to be_kind_of(PermissionPolicy::Authorization)
29
+ end
30
+
31
+ it 'is initialized with preconditions' do
32
+ expect(subject.permission_policy.foo).to eq('foo')
33
+ expect(subject.permission_policy.bar).to eq('bar')
34
+ end
35
+ end
36
+
37
+ context 'helpers' do
38
+ it { is_expected.to respond_to :authorize! }
39
+ it { is_expected.to respond_to :allowed? }
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ module PermissionPolicy
2
+ module Strategies
3
+ RSpec.describe BaseStrategy do
4
+
5
+ context 'valid' do
6
+ let(:authorization) { double('authorization', preconditions: [:current_user], current_user: 'me') }
7
+ let(:action) { :foo }
8
+ let(:options) { { something: 'nice' } }
9
+
10
+ subject { described_class.new(authorization, action, options) }
11
+
12
+ it 'sets dynamic attributes' do
13
+ expect(subject.current_user).to eq('me')
14
+ end
15
+
16
+ it 'sets action' do
17
+ expect(subject.action).to eq(:foo)
18
+ end
19
+
20
+ it 'sets options' do
21
+ expect(subject.options[:something]).to eq('nice')
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,8 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'permission_policy'
4
+
5
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
1
6
 
2
7
  RSpec.configure do |config|
3
8
  # The settings below are suggested to provide a good initial experience
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: permission_policy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Schaden
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-08 00:00:00.000000000 Z
12
+ date: 2015-01-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: 3.0.0
20
+ version: 4.0.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: 3.0.0
27
+ version: 4.0.0
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: bundler
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -53,6 +53,20 @@ dependencies:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: 3.0.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: guard-rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
56
70
  - !ruby/object:Gem::Dependency
57
71
  name: rake
58
72
  requirement: !ruby/object:Gem::Requirement
@@ -81,6 +95,34 @@ dependencies:
81
95
  - - ">="
82
96
  - !ruby/object:Gem::Version
83
97
  version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rubocop
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: actionpack
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: 4.0.0
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: 4.0.0
84
126
  description: Expandable object oriented authorization solution for Ruby/Rails applications
85
127
  email:
86
128
  - marco@railslove.com
@@ -91,13 +133,27 @@ extra_rdoc_files: []
91
133
  files:
92
134
  - ".gitignore"
93
135
  - ".rspec"
136
+ - ".rubocop.yml"
94
137
  - Gemfile
138
+ - Guardfile
95
139
  - LICENSE.txt
96
140
  - README.md
97
141
  - Rakefile
98
142
  - lib/permission_policy.rb
143
+ - lib/permission_policy/authorization.rb
144
+ - lib/permission_policy/configuration.rb
145
+ - lib/permission_policy/controller_additions.rb
146
+ - lib/permission_policy/errors/missing_precondition.rb
147
+ - lib/permission_policy/errors/not_allowed.rb
148
+ - lib/permission_policy/railtie.rb
149
+ - lib/permission_policy/strategies/base_strategy.rb
150
+ - lib/permission_policy/strategies/unknown_strategy.rb
99
151
  - lib/permission_policy/version.rb
100
152
  - permission_policy.gemspec
153
+ - spec/permission_policy/authorization_spec.rb
154
+ - spec/permission_policy/configuration_spec.rb
155
+ - spec/permission_policy/controller_additions_spec.rb
156
+ - spec/permission_policy/strategies/base_strategy_spec.rb
101
157
  - spec/spec_helper.rb
102
158
  homepage: ''
103
159
  licenses:
@@ -124,4 +180,8 @@ signing_key:
124
180
  specification_version: 4
125
181
  summary: Without order, there is chaos
126
182
  test_files:
183
+ - spec/permission_policy/authorization_spec.rb
184
+ - spec/permission_policy/configuration_spec.rb
185
+ - spec/permission_policy/controller_additions_spec.rb
186
+ - spec/permission_policy/strategies/base_strategy_spec.rb
127
187
  - spec/spec_helper.rb