exits 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NzNjOGQ5NjQyZGI4NGEzNWZhMTNiYTAwZDMzNmMzYTAwOTQ4ZGUxMw==
5
+ data.tar.gz: !binary |-
6
+ NDQwMjQ3ODYzNmE0MTBmNWM0NDYzODlkYWY3NzZlYWFlYWE1MGRkOA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ OTA3Nzc3ZmM0N2I5NmEyZWZkYWU2OGJmYTY0OTU3MzZiNmYwZWVlNTc0ZGYy
10
+ ZmM4ODY4MTVlOWVhY2EwMjRjOGFjZTAzMmNhZDc5MmJhMWYyMjY1M2U0ZWNi
11
+ OTc3NGVmYTEzMjE2ZWNlMmZjMGMzYjg5NzhkN2IwOWY5MGZhYmE=
12
+ data.tar.gz: !binary |-
13
+ MTI3MWFmZjhiM2U1Y2NlY2I2Njg1NjUwOTQ5NzRkNzcwNmFkZTk1ZjhmZDE2
14
+ NTJiZGJiMDE0YzhlM2I5NmI1NDJjMTVhNmU3NzdlOTExZTQxYjA3ZjczZGVk
15
+ ZGI1M2M2MzI4MDU4YWQ2NjRlMjc5NDQ3ZWI3YWM2ZGU1YjRiMTI=
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in exits.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Pier-Olivier Thibault
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Exits
2
+ When you want to restrict access to your Rails application.
3
+
4
+ ## Description
5
+ You want to restrict access to your application so Administrator & User can have different access level. Exits provides two level of authorization that works in conjunction so you can fine tuned access to your need. All the authorization logic is set in the *controller* to make it easy for you to figure out who has access to what.
6
+
7
+ Designed with an emphasis on readability, it also is designed to work with your authentication setup(Warden, Devise).
8
+
9
+
10
+ ## How to use
11
+
12
+ Let's assume you have Admin & User and want to let admin have access to everything and restrict User to edit their own stuff.
13
+
14
+ # controllers/application_controller.rb
15
+ class ApplicationController < ActionController::Base
16
+ before_action :restrict_routes!
17
+ end
18
+
19
+ # controllers/posts_controller.rb
20
+ class PostsController < ActionController::Base
21
+ allow Admin, :all
22
+ allow User, :show, :new, :create, :edit
23
+
24
+ def admin
25
+ end
26
+
27
+ def edit
28
+ @post = Post.find params[:id].to_i
29
+ allow! User do
30
+ current_user.eql? @post.user
31
+ end
32
+ end
33
+ end
34
+
35
+ First of all, for Exits to work, you need to add `before_action :restrict_routes` to your ApplicationController.
36
+
37
+ Exits takes a very strict approach to handling access. If you don't allow access to an action for a given user class, _it won't be authorized to access such action._
38
+
39
+ This is by designed, it's a tradeoff between boilerplate code & readability. It's much easier to understand permissions if they are explicit in every controller and presented in the same manner throughout your application.
40
+
41
+ To give access to a controller, you have to use `allow` the class as shown above in PostsController[line 2-3].
42
+
43
+ If you need to be more specific about a permission, you can be more precise inside the controller method using `allow!`. This method takes a block that needs to return _true_ or _false_.
44
+
45
+ If it returns false, Exits will raise an exception and redirect you to :root (You can customize this behavior).
46
+
47
+ *Remember:* You have to set permission inside your controller's class. If a user class does not have permission to access the controller, it will never reach the controller's method! e.g PostsController#edit
48
+
49
+ ### Unauthorized
50
+ When a user is unauthorized the default behavior is to set a flash message and redirect to :root.
51
+
52
+ You can override this behavior.
53
+
54
+ # controllers/application_controller.rb
55
+ class ApplicationController < ActionController::Base
56
+ before_action :restrict_routes!
57
+
58
+ def unauthorized (exception)
59
+ # Handle unauthorized user here
60
+ end
61
+ end
62
+
63
+
64
+ ## Installation
65
+
66
+ Add this line to your application's Gemfile:
67
+
68
+ gem 'exits'
69
+
70
+ And then execute:
71
+
72
+ $ bundle
73
+
74
+ ## Test
75
+ Exits comes with a test suite.
76
+
77
+ $ rake test
78
+
79
+ ## Contributing
80
+
81
+ 1. Fork it
82
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
83
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
84
+ 4. Push to the branch (`git push origin my-new-feature`)
85
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ Rake::TestTask.new do |t|
7
+ end
8
+
9
+ desc 'Run test suite'
10
+ task :default => :test
11
+
data/exits.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'exits/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "exits"
8
+ spec.version = Exits::VERSION
9
+ spec.authors = ["Pier-Olivier Thibault"]
10
+ spec.email = ["pothibo@gmail.com"]
11
+ spec.description = %q{Exits authorize user to access specific part of your application with a clear syntax}
12
+ spec.summary = %q{Authorization for your rails' application}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activesupport", ">= 4.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency 'minitest', "~> 4.2"
26
+ end
@@ -0,0 +1,52 @@
1
+ require 'active_support'
2
+
3
+ module Exits
4
+ module ActionController
5
+ module Helpers
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ rescue_from Exits::Rules::Unauthorized do |exception|
10
+ unauthorized exception
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ def allow(kls, *actions)
17
+ rules.add self, kls, actions
18
+ end
19
+
20
+ def rules
21
+ @rules ||= ::Exits::Rules.new
22
+ end
23
+
24
+ end
25
+
26
+ def restrict_routes!
27
+ unless self.class.rules.authorized?(self.class, current_user.class, action_name)
28
+ restricted!
29
+ end
30
+ end
31
+
32
+ protected
33
+
34
+ def unauthorized(exception)
35
+ flash.alert = t("exits.unauthorized")
36
+ redirect_to :root
37
+ end
38
+
39
+ def allow!(kls, &block)
40
+ return unless current_user.instance_of?(kls)
41
+ unless yield
42
+ restricted!
43
+ end
44
+ end
45
+
46
+ def restricted!
47
+ raise Exits::Rules::Unauthorized
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ require 'exits/action_controller/helpers'
2
+
3
+ module Exits
4
+ class Railtie < ::Rails::Railtie
5
+ initializer "exits.railties.initializer" do |app|
6
+ ActiveSupport.on_load :action_controller do
7
+ include Exits::ActionController::Helpers
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module Exits
2
+ class Rules
3
+ class Controller
4
+ def initialize
5
+ @users = {}
6
+ end
7
+
8
+ def []=(user_class, actions)
9
+ @users[user_class] ||= Exits::Rules::User.new
10
+ @users[user_class].allow actions
11
+ end
12
+
13
+ def [](user_class)
14
+ @users[user_class]
15
+ end
16
+
17
+ def authorized?(klass, action)
18
+ user = self[klass]
19
+ return false if user.nil?
20
+ user.authorized? action
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ module Exits
2
+ class Rules
3
+ class User
4
+ class Exits::Rules::ConfusingRulesError < StandardError; end;
5
+ def initialize
6
+ @actions = []
7
+ end
8
+
9
+ def allow(*actions)
10
+ @actions = @actions | actions.flatten
11
+
12
+ if @actions.size > 1 && @actions.include?(:all)
13
+ raise Exits::Rules::ConfusingRulesError, "You have :all and specific actions within the same controller/user rule."
14
+ end
15
+ end
16
+
17
+ def authorized?(action)
18
+ return true if @actions.include?(:all)
19
+ return @actions.include?(action)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,23 @@
1
+ require 'exits/rules/controller'
2
+ require 'exits/rules/user'
3
+
4
+ module Exits
5
+ class Rules
6
+ class Unauthorized < StandardError; end;
7
+
8
+ def initialize
9
+ @controllers = Hash.new
10
+ end
11
+
12
+ def add(controller_class, klass, *actions)
13
+ @controllers[controller_class] ||= Exits::Rules::Controller.new
14
+ @controllers[controller_class][klass] = actions.flatten
15
+ end
16
+
17
+ def authorized?(controller_class, klass, action)
18
+ controller = @controllers.fetch(controller_class, {})
19
+ return false if controller.nil?
20
+ controller.authorized? klass, action
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module Exits
2
+ VERSION = "0.0.2"
3
+ end
data/lib/exits.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "exits/version"
2
+ require 'exits/rules'
3
+
4
+ module Exits
5
+
6
+ end
7
+
8
+ if defined? Rails
9
+ require 'exits/railtie'
10
+ end
@@ -0,0 +1,80 @@
1
+ gem 'minitest'
2
+ require 'minitest/autorun'
3
+ require 'exits/rules'
4
+ require 'exits/action_controller/helpers'
5
+
6
+ class User
7
+ attr_accessor :id
8
+ end
9
+
10
+ class Admin < User; end;
11
+
12
+ class SomeController
13
+ include ActiveSupport::Rescuable
14
+ include Exits::ActionController::Helpers
15
+ attr_accessor :action_name, :current_user
16
+
17
+ allow Admin, :all
18
+ allow User, :show, :index
19
+
20
+ def index
21
+ @user = User.new
22
+ @user.id = 1
23
+ allow! User do
24
+ current_user.id == @user.id
25
+ end
26
+ return true
27
+ end
28
+
29
+ end
30
+
31
+
32
+ describe Exits::ActionController::Helpers do
33
+ def setup
34
+ @controller = SomeController.new
35
+ end
36
+
37
+ it 'should not authorize a user at the controller level' do
38
+ @controller.action_name = :edit
39
+ @controller.current_user = User.new
40
+
41
+ assert_raises Exits::Rules::Unauthorized do
42
+ @controller.send(:restrict_routes!)
43
+ end
44
+ end
45
+
46
+ it 'should not authorize a user at the action level' do
47
+ @controller.action_name = :edit
48
+ @controller.current_user = User.new
49
+
50
+ assert_raises Exits::Rules::Unauthorized do
51
+ @controller.index
52
+ end
53
+ end
54
+
55
+ it 'should authorize a user' do
56
+ @controller.action_name = :show
57
+ assert @controller.class.rules.authorized? @controller.class, User, @controller.action_name
58
+ end
59
+
60
+ it "should not authorize a user if he is not allowed within the action" do
61
+ @user = User.new
62
+ @user.id = 2
63
+ @controller.action_name = :index
64
+ @controller.current_user = @user
65
+ assert_raises Exits::Rules::Unauthorized do
66
+ @controller.index
67
+ end
68
+ end
69
+
70
+ it "should allow a user only if he's cleared the 2 levels" do
71
+ @user = User.new
72
+ @user.id = 1
73
+ @controller.action_name = :index
74
+ @controller.current_user = @user
75
+ assert @controller.class.rules.authorized?(@controller.class, @user.class, @controller.action_name), "Should be allowed on the controller level"
76
+ assert @controller.index, "Should be allowed on the action level"
77
+ end
78
+
79
+ end
80
+
@@ -0,0 +1,86 @@
1
+ gem 'minitest'
2
+ require 'minitest/autorun'
3
+ require 'exits/rules'
4
+
5
+ class SomeController; end;
6
+ class User; end;
7
+
8
+ describe Exits::Rules do
9
+ def setup
10
+ @rules = Exits::Rules.new
11
+ end
12
+
13
+ describe Exits::Rules::User do
14
+ def setup
15
+ @rule = Exits::Rules::User.new
16
+ end
17
+
18
+ it 'should not authorize if no rules have been set' do
19
+ assert !@rule.authorized?(:show), "Shouldn't authorize :show"
20
+ end
21
+
22
+ it 'should be able to allow an action' do
23
+ @rule.allow(:show)
24
+ assert @rule.authorized?(:show), "Couldn't authorize :show"
25
+ end
26
+
27
+ it 'should make sure actions are unique' do
28
+ @rule.allow(:show, :show)
29
+ assert @rule.instance_variable_get("@actions").size == 1, "Should only be 1 instance of :show"
30
+ end
31
+
32
+ it 'should make a union of every call to Exits::Rules::User#allow' do
33
+ @rule.allow(:show)
34
+ @rule.allow(:show, :edit)
35
+ actions = @rule.instance_variable_get("@actions")
36
+
37
+ assert_equal [:show, :edit], actions, "Should only be 2 actions registered"
38
+ end
39
+
40
+ it 'should raise an error if :all is set with other actions' do
41
+ assert_raises Exits::Rules::ConfusingRulesError do
42
+ @rule.allow(:show)
43
+ @rule.allow(:all)
44
+ end
45
+ end
46
+
47
+ it 'should authorize any action if :all is set' do
48
+ @rule.allow(:all)
49
+ assert @rule.authorized?(:show), "Should authorize :show when :all is set"
50
+ end
51
+ end
52
+
53
+ describe Exits::Rules::Controller do
54
+ def setup
55
+ @rule = Exits::Rules::Controller.new
56
+ end
57
+
58
+ it 'should not authorize if no rules have been set' do
59
+ assert !@rule.authorized?(User, :show), "Shouldn't authorize User if there's no rule"
60
+ end
61
+
62
+ it 'should be able to add a rule & authorize' do
63
+ @rule[User] = :show, :edit
64
+ assert @rule.authorized?(User, :show), "Should authorize :show for User"
65
+ end
66
+
67
+ end
68
+
69
+ it 'should be able to add rules' do
70
+ @rules.add SomeController, User, [:show]
71
+ controllers = @rules.instance_variable_get("@controllers")
72
+ assert controllers.has_key?(SomeController), "No rules for #{SomeController.name}"
73
+ assert !controllers[SomeController][User].nil?, "Couldn't add a rule for #{User.name}"
74
+ end
75
+
76
+ it 'should authorize a user matching the rule' do
77
+ @rules.add SomeController, User, [:show]
78
+ assert @rules.authorized?(SomeController, User, :show), "Couldn't authorize User in SomeController for :show"
79
+ end
80
+
81
+ it 'should prohibit a user accessing an undefined action' do
82
+ @rules.add SomeController, User, [:show]
83
+ assert !@rules.authorized?(SomeController, User, :edit), "Shouldn't authorize User in SomeController for :edit"
84
+ end
85
+ end
86
+
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: exits
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Pier-Olivier Thibault
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '4.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '4.2'
69
+ description: Exits authorize user to access specific part of your application with
70
+ a clear syntax
71
+ email:
72
+ - pothibo@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - exits.gemspec
83
+ - lib/exits.rb
84
+ - lib/exits/action_controller/helpers.rb
85
+ - lib/exits/railtie.rb
86
+ - lib/exits/rules.rb
87
+ - lib/exits/rules/controller.rb
88
+ - lib/exits/rules/user.rb
89
+ - lib/exits/version.rb
90
+ - test/test_controller.rb
91
+ - test/test_rules.rb
92
+ homepage: ''
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.0.3
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Authorization for your rails' application
116
+ test_files:
117
+ - test/test_controller.rb
118
+ - test/test_rules.rb