openstax_utilities 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +28 -1
  3. data/Rakefile +12 -41
  4. data/lib/openstax/utilities/access_policy.rb +54 -0
  5. data/lib/openstax/utilities/controller_extensions.rb +47 -0
  6. data/lib/openstax/utilities/engine.rb +6 -0
  7. data/lib/openstax/utilities/version.rb +1 -1
  8. data/lib/openstax_utilities.rb +2 -0
  9. data/spec/dummy/README.md +1 -0
  10. data/{test → spec}/dummy/Rakefile +0 -0
  11. data/spec/dummy/app/access_policies/dummy_access_policy.rb +10 -0
  12. data/{test → spec}/dummy/app/assets/javascripts/application.js +0 -0
  13. data/{test → spec}/dummy/app/assets/stylesheets/application.css +0 -0
  14. data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
  15. data/{test → spec}/dummy/app/controllers/application_controller.rb +2 -0
  16. data/spec/dummy/app/controllers/users_controller.rb +87 -0
  17. data/{test → spec}/dummy/app/helpers/application_helper.rb +0 -0
  18. data/spec/dummy/app/models/user.rb +2 -0
  19. data/{test → spec}/dummy/app/views/layouts/application.html.erb +0 -0
  20. data/spec/dummy/app/views/users/_form.html.erb +17 -0
  21. data/spec/dummy/app/views/users/edit.html.erb +6 -0
  22. data/spec/dummy/app/views/users/index.html.erb +21 -0
  23. data/spec/dummy/app/views/users/new.html.erb +5 -0
  24. data/spec/dummy/app/views/users/show.html.erb +5 -0
  25. data/{test → spec}/dummy/config/application.rb +0 -0
  26. data/{test → spec}/dummy/config/boot.rb +0 -0
  27. data/{test → spec}/dummy/config/database.yml +0 -0
  28. data/{test → spec}/dummy/config/environment.rb +0 -0
  29. data/{test → spec}/dummy/config/environments/development.rb +0 -0
  30. data/{test → spec}/dummy/config/environments/production.rb +0 -0
  31. data/{test → spec}/dummy/config/environments/test.rb +0 -0
  32. data/{test → spec}/dummy/config/initializers/backtrace_silencers.rb +0 -0
  33. data/{test → spec}/dummy/config/initializers/inflections.rb +0 -0
  34. data/{test → spec}/dummy/config/initializers/mime_types.rb +0 -0
  35. data/{test → spec}/dummy/config/initializers/secret_token.rb +0 -0
  36. data/{test → spec}/dummy/config/initializers/session_store.rb +0 -0
  37. data/{test → spec}/dummy/config/initializers/wrap_parameters.rb +0 -0
  38. data/{test → spec}/dummy/config/locales/en.yml +0 -0
  39. data/spec/dummy/config/routes.rb +5 -0
  40. data/{test → spec}/dummy/config.ru +0 -0
  41. data/spec/dummy/db/migrate/0_create_users.rb +10 -0
  42. data/spec/dummy/db/schema.rb +23 -0
  43. data/{test → spec}/dummy/public/404.html +0 -0
  44. data/{test → spec}/dummy/public/422.html +0 -0
  45. data/{test → spec}/dummy/public/500.html +0 -0
  46. data/{test → spec}/dummy/public/favicon.ico +0 -0
  47. data/{test → spec}/dummy/script/rails +0 -0
  48. data/spec/lib/openstax/utilities/access_policy_spec.rb +67 -0
  49. data/spec/lib/openstax/utilities/controller_extensions_spec.rb +29 -0
  50. data/spec/lib/openstax/utilities/extended_controller_spec.rb +82 -0
  51. data/spec/spec_helper.rb +17 -0
  52. metadata +120 -62
  53. data/test/dummy/README.rdoc +0 -261
  54. data/test/dummy/config/routes.rb +0 -4
  55. data/test/integration/navigation_test.rb +0 -10
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YWZhYmU2NTY1MjJiZDNiNTE1YTFiZDI1YTk0YzcwYmY3ODAzZmEzMg==
4
+ NzdiOTJlYTJhMThlMWQzYjI0MGVkYWI1NzRlNjdlZmUyNmJmMzdlOQ==
5
5
  data.tar.gz: !binary |-
6
- YWRhMTg0MmIyMmM3NGMzYzk4OWRlNWNmYTQ3NjA5MGYxMzdmMDNiZA==
6
+ YTQzYTI0YTEzMTQxZDZmZTNkNzQ0OWNkZGI2OWMwZWU5ZjQ3ZjA1ZQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZmEyNjIwM2YxMDI5YjkxNDc4MWUyM2NlZDhmZGVjZDYyNzZmMGQ5ZTJlMGI1
10
- OTVjMjAxZDYxMTg0Yjg4ODljMDk4MWUxODIxMWYxOTMwZWY0NDI3MWRlNmUw
11
- NzM5MjJmMmFkNDE1NmM0ZGY2MTdmMjljMGFhYzljZjdiN2I0YTA=
9
+ MjBhYTQ2NTc2ODAxNDgxYjhhYzFjYWVhYzFlZWJiOWMyMjBmN2Y5MzExYzgz
10
+ ZDdmZmI3N2RlMDgzMzMyMmUzMmFhOWVhNjk5OGIyYTdmZGUxNTEzZjY3YjRk
11
+ OWFlNTMxNmE0MzkzOWU4M2NlODIwMTk3ZDhlNGEzNGE3Njk0NTM=
12
12
  data.tar.gz: !binary |-
13
- Mjc1YjE5MTYwMjZiM2RkMzQ3MGY3MmMxOGQ3ZjI3NGU0MGU3MDI3MjFmYTBi
14
- YzhmY2YzMDU3OWU5NWZmNDkxZGM5OTg4MTI4NDVjYmQxMGE5NTA1Y2EzNWNk
15
- NWNjNzE1ZGU1MjRiMTY2OWRkMWVkMzk2MGViNDc3ZWI1ZDk5NTQ=
13
+ YzYyY2Y0ZTMxOGQ3NGYxZTg3Y2M0NWEzNjZlNDI0N2RmMmYzYzkxMTg2OTk2
14
+ YWFjOTc4YjI2NDcxYTJkZTA3ZjgxNDdmMjM1NjhiMDFlZmVkOGYzZjM5Yzlj
15
+ YWNhYTlmNjM5NjlmODQyYTNjYWU5MGUxODQ2NjI5OTE1NmJhZGY=
data/README.md CHANGED
@@ -9,4 +9,31 @@ To use this utility engine, include it in your Gemfile.
9
9
 
10
10
  ## Helpers
11
11
 
12
- This engine's helpers are available in the main application by preceding them with `osu.`, e.g. `osu.section_block('Heading') { "guts" }`
12
+ This engine's helpers are available in the main application by preceding them with `osu.`, e.g. `osu.section_block('Heading') { "guts" }`
13
+
14
+ ## Access Policies
15
+
16
+ As applications grow to include different kinds of users, including signed-in and anonymous human users, as well as other applications, the logic for controlling which user has which accesses to which resources can grow complex. Controllers certainly aren't the place for this logic. In a case with one kind of User, models *may* be the place for this logic but even then this makes models know way too much about other models.
17
+
18
+ Access Policies were created to be a dedicated place to store the logic controlling who has access to what. All other code can ask the `AccessPolicy` class for this info, via the `action_allowed?` or the convenience methods `read_allowed?`, `create_allowed?`, etc. `AccessPolicy` then delegates the access decisions off to other policy classes, of which there is normally one per kind of resource (e.g. a `UserAccessPolicy`, `ContactInfoPolicy`, etc).
19
+
20
+ These resource-specific policy classes register themselves with the main `AccessPolicy` class, telling `AccessPolicy` what kinds of resources they can handle. E.g. the `UserAccessPolicy` tells `AccessPolicy` it handles permissions for `User` with the following call:
21
+
22
+ ```rb
23
+ OSU::AccessPolicy.register(User, UserAccessPolicy)
24
+ ```
25
+
26
+ This call is typically made after the policy class' definition so that it is called when the Rails application is loaded. We recommend placing the policy classes under `app/access_policies`, as all files under the `app` directory are autoloaded by Rails.
27
+
28
+ ## Controller Extensions
29
+
30
+ The following methods will be added to all controllers:
31
+
32
+ `get_model(id_param, klass)` tries to use the id_param to return the model in question for
33
+ restful actions, or a new instance of klass if the id could not be found.
34
+ (e.g. on :new, :create and even :index)
35
+ By default, id_param is :id and klass is controller_name.classify.constantize.
36
+
37
+ `self.require_restful_actions_allowed!(options)` adds a before_filter that calls AccessPolicy.require_action_allowed! for all restful actions except :index. So by default it will add checks to :show, :new, :create, :edit, :update and :destroy.
38
+ options is a hash that contains any desired before_filter options, plus the optional keys :id_param and :model_class, which are passed to get_model instead.
39
+ By default, options is an empty hash.
data/Rakefile CHANGED
@@ -1,48 +1,19 @@
1
1
  #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
2
7
 
3
- require 'bundler/gem_tasks'
8
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
9
+ load 'rails/tasks/engine.rake'
4
10
 
5
- # begin
6
- # require 'bundler/setup'
7
- # rescue LoadError
8
- # puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
9
- # end
10
- # begin
11
- # require 'rdoc/task'
12
- # rescue LoadError
13
- # require 'rdoc/rdoc'
14
- # require 'rake/rdoctask'
15
- # RDoc::Task = Rake::RDocTask
16
- # end
17
-
18
- # RDoc::Task.new(:rdoc) do |rdoc|
19
- # rdoc.rdoc_dir = 'rdoc'
20
- # rdoc.title = 'OpenstaxUtilities'
21
- # rdoc.options << '--line-numbers'
22
- # rdoc.rdoc_files.include('README.rdoc')
23
- # rdoc.rdoc_files.include('lib/**/*.rb')
24
- # end
25
-
26
- # APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
27
-
28
-
29
- # Bundler::GemHelper.install_tasks
30
-
31
- # # require 'rake/testtask'
32
-
33
- # # Rake::TestTask.new(:test) do |t|
34
- # # t.libs << 'lib'
35
- # # t.libs << 'test'
36
- # # t.pattern = 'test/**/*_test.rb'
37
- # # t.verbose = false
38
- # # end
39
-
40
-
41
- # # task :default => :test
11
+ Bundler::GemHelper.install_tasks
42
12
 
13
+ require 'rspec/core'
43
14
  require 'rspec/core/rake_task'
44
15
 
45
- RSpec::Core::RakeTask.new('spec')
16
+ desc "Run all specs in spec directory (excluding plugin specs)"
17
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
46
18
 
47
- # If you want to make this the default task
48
- task :default => :spec
19
+ task :default => :spec
@@ -0,0 +1,54 @@
1
+ # See the README
2
+
3
+ module OpenStax
4
+ module Utilities
5
+ class AccessPolicy
6
+ include Singleton
7
+
8
+ attr_reader :resource_policy_map
9
+
10
+ def initialize()
11
+ @resource_policy_map = {}
12
+ end
13
+
14
+ def self.method_missing(method_name, *arguments, &block)
15
+ if method_name.to_s =~ /(.*)_allowed?/
16
+ action_allowed?(*arguments.unshift($1.to_sym), &block)
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def self.respond_to_missing?(method_name, include_private = false)
23
+ method_name.to_s.end_with?('_allowed?') || super
24
+ end
25
+
26
+ def self.require_action_allowed!(action, requestor, resource)
27
+ raise SecurityTransgression unless action_allowed?(action, requestor, resource)
28
+ end
29
+
30
+ def self.action_allowed?(action, requestor, resource)
31
+
32
+ # If the incoming requestor is an ApiUser, choose to use either its
33
+ # human_user or its application. If there is a human user involved, it
34
+ # should always take precedence when testing for access.
35
+ if defined?(ApiUser) && requestor.is_a?(ApiUser)
36
+ requestor = requestor.human_user ? requestor.human_user : requestor.application
37
+ end
38
+
39
+ resource_class = resource.is_a?(Class) ? resource : resource.class
40
+ policy_class = instance.resource_policy_map[resource_class.to_s]
41
+
42
+ # If there is no policy registered, we by default deny access
43
+ return false if policy_class.nil?
44
+
45
+ policy_class.action_allowed?(action, requestor, resource)
46
+ end
47
+
48
+ def self.register(resource_class, policy_class)
49
+ self.instance.resource_policy_map[resource_class.to_s] = policy_class
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,47 @@
1
+ module OpenStax
2
+ module Utilities
3
+ module ControllerExtensions
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ # Tries to find model if id is given, or returns a new model if not
9
+ def get_model(id_param = nil, klass = nil)
10
+ id_param ||= :id
11
+ id = params[id_param]
12
+ klass ||= controller_name.classify.constantize
13
+ id.nil? ? klass.new : klass.find(id)
14
+ end
15
+
16
+ module ClassMethods
17
+ # Calls AccessPolicy.require_action_allowed! on all restful actions
18
+ # For create and update, the new params are not yet set
19
+ def require_restful_actions_allowed!(options = {})
20
+ class_eval do
21
+ before_filter({:only => [:show, :new, :create, :edit, :update,
22
+ :destroy]}.merge(options.except(:id_param,
23
+ :model_class))) do |c|
24
+
25
+ case c.action_name
26
+ when 'show'
27
+ action = :read
28
+ when 'new'
29
+ action = :create
30
+ when 'edit'
31
+ action = :update
32
+ else
33
+ action = c.action_name.to_sym
34
+ end
35
+
36
+ OSU::AccessPolicy.require_action_allowed!(action,
37
+ c.current_user, c.get_model(options[:id_param],
38
+ options[:model_class]))
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ ActionController::Base.send :include, OpenStax::Utilities::ControllerExtensions
@@ -16,6 +16,12 @@ module OpenStax
16
16
  helper OSU::OsuHelper
17
17
  end
18
18
  end
19
+
20
+ config.generators do |g|
21
+ g.test_framework :rspec, :fixture => false
22
+ g.assets false
23
+ g.helper false
24
+ end
19
25
  end
20
26
  end
21
27
  end
@@ -1,5 +1,5 @@
1
1
  module OpenStax
2
2
  module Utilities
3
- VERSION = "2.0.0"
3
+ VERSION = "2.1.0"
4
4
  end
5
5
  end
@@ -19,6 +19,8 @@ require "openstax/utilities/action_list"
19
19
  require "openstax/utilities/acts_as_numberable"
20
20
  require "openstax/utilities/delegate_access_control"
21
21
  require "openstax/utilities/roar"
22
+ require "openstax/utilities/access_policy"
23
+ require "openstax/utilities/controller_extensions"
22
24
 
23
25
  require "openstax/utilities/classy_helper"
24
26
  require "openstax/utilities/helpers/misc"
@@ -0,0 +1 @@
1
+ Dummy application used to test the openstax_utilities gem.
File without changes
@@ -0,0 +1,10 @@
1
+ class DummyAccessPolicy
2
+ cattr_accessor :last_action, :last_requestor, :last_resource
3
+
4
+ def self.action_allowed?(action, requestor, resource)
5
+ @@last_action = action
6
+ @@last_requestor = requestor
7
+ @@last_resource = resource
8
+ true
9
+ end
10
+ end
@@ -0,0 +1,56 @@
1
+ body { background-color: #fff; color: #333; }
2
+
3
+ body, p, ol, ul, td {
4
+ font-family: verdana, arial, helvetica, sans-serif;
5
+ font-size: 13px;
6
+ line-height: 18px;
7
+ }
8
+
9
+ pre {
10
+ background-color: #eee;
11
+ padding: 10px;
12
+ font-size: 11px;
13
+ }
14
+
15
+ a { color: #000; }
16
+ a:visited { color: #666; }
17
+ a:hover { color: #fff; background-color:#000; }
18
+
19
+ div.field, div.actions {
20
+ margin-bottom: 10px;
21
+ }
22
+
23
+ #notice {
24
+ color: green;
25
+ }
26
+
27
+ .field_with_errors {
28
+ padding: 2px;
29
+ background-color: red;
30
+ display: table;
31
+ }
32
+
33
+ #error_explanation {
34
+ width: 450px;
35
+ border: 2px solid red;
36
+ padding: 7px;
37
+ padding-bottom: 0;
38
+ margin-bottom: 20px;
39
+ background-color: #f0f0f0;
40
+ }
41
+
42
+ #error_explanation h2 {
43
+ text-align: left;
44
+ font-weight: bold;
45
+ padding: 5px 5px 5px 15px;
46
+ font-size: 12px;
47
+ margin: -7px;
48
+ margin-bottom: 0px;
49
+ background-color: #c00;
50
+ color: #fff;
51
+ }
52
+
53
+ #error_explanation ul li {
54
+ font-size: 12px;
55
+ list-style: square;
56
+ }
@@ -1,3 +1,5 @@
1
1
  class ApplicationController < ActionController::Base
2
2
  protect_from_forgery
3
+
4
+ attr_accessor :current_user
3
5
  end
@@ -0,0 +1,87 @@
1
+ class UsersController < ApplicationController
2
+ # GET /users
3
+ # GET /users.json
4
+ def index
5
+ @users = User.all
6
+
7
+ respond_to do |format|
8
+ format.html # index.html.erb
9
+ format.json { render json: @users }
10
+ end
11
+ end
12
+
13
+ # GET /users/1
14
+ # GET /users/1.json
15
+ def show
16
+ @user = User.find(params[:id])
17
+
18
+ respond_to do |format|
19
+ format.html # show.html.erb
20
+ format.json { render json: @user }
21
+ end
22
+ end
23
+
24
+ # GET /users/new
25
+ # GET /users/new.json
26
+ def new
27
+ @user = User.new
28
+
29
+ respond_to do |format|
30
+ format.html # new.html.erb
31
+ format.json { render json: @user }
32
+ end
33
+ end
34
+
35
+ # GET /users/1/edit
36
+ def edit
37
+ @user = User.find(params[:id])
38
+ end
39
+
40
+ # POST /users
41
+ # POST /users.json
42
+ def create
43
+ @user = User.new
44
+ @user.username = params[:user][:username]
45
+ @user.password_hash = SecureRandom.hex(32)
46
+
47
+ respond_to do |format|
48
+ if @user.save
49
+ format.html { redirect_to @user, notice: 'User was successfully created.' }
50
+ format.json { render json: @user, status: :created, location: @user }
51
+ else
52
+ format.html { render action: "new" }
53
+ format.json { render json: @user.errors, status: :unprocessable_entity }
54
+ end
55
+ end
56
+ end
57
+
58
+ # PUT /users/1
59
+ # PUT /users/1.json
60
+ def update
61
+ @user = User.find(params[:id])
62
+ @user.username = params[:user][:username]
63
+ @user.password_hash = SecureRandom.hex(32)
64
+
65
+ respond_to do |format|
66
+ if @user.save
67
+ format.html { redirect_to @user, notice: 'User was successfully updated.' }
68
+ format.json { head :no_content }
69
+ else
70
+ format.html { render action: "edit" }
71
+ format.json { render json: @user.errors, status: :unprocessable_entity }
72
+ end
73
+ end
74
+ end
75
+
76
+ # DELETE /users/1
77
+ # DELETE /users/1.json
78
+ def destroy
79
+ @user = User.find(params[:id])
80
+ @user.destroy
81
+
82
+ respond_to do |format|
83
+ format.html { redirect_to users_url }
84
+ format.json { head :no_content }
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,2 @@
1
+ class User < ActiveRecord::Base
2
+ end
@@ -0,0 +1,17 @@
1
+ <%= form_for(@user) do |f| %>
2
+ <% if @user.errors.any? %>
3
+ <div id="error_explanation">
4
+ <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
5
+
6
+ <ul>
7
+ <% @user.errors.full_messages.each do |msg| %>
8
+ <li><%= msg %></li>
9
+ <% end %>
10
+ </ul>
11
+ </div>
12
+ <% end %>
13
+
14
+ <div class="actions">
15
+ <%= f.submit %>
16
+ </div>
17
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <h1>Editing user</h1>
2
+
3
+ <%= render 'form' %>
4
+
5
+ <%= link_to 'Show', @user %> |
6
+ <%= link_to 'Back', users_path %>
@@ -0,0 +1,21 @@
1
+ <h1>Listing users</h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <th></th>
6
+ <th></th>
7
+ <th></th>
8
+ </tr>
9
+
10
+ <% @users.each do |user| %>
11
+ <tr>
12
+ <td><%= link_to 'Show', user %></td>
13
+ <td><%= link_to 'Edit', edit_user_path(user) %></td>
14
+ <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
15
+ </tr>
16
+ <% end %>
17
+ </table>
18
+
19
+ <br />
20
+
21
+ <%= link_to 'New User', new_user_path %>
@@ -0,0 +1,5 @@
1
+ <h1>New user</h1>
2
+
3
+ <%= render 'form' %>
4
+
5
+ <%= link_to 'Back', users_path %>
@@ -0,0 +1,5 @@
1
+ <p id="notice"><%= notice %></p>
2
+
3
+
4
+ <%= link_to 'Edit', edit_user_path(@user) %> |
5
+ <%= link_to 'Back', users_path %>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ resources :users
3
+
4
+ mount OpenStax::Utilities::Engine => "/openstax_utilities"
5
+ end
File without changes
@@ -0,0 +1,10 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :username
5
+ t.string :password_hash
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended to check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(:version => 0) do
15
+
16
+ create_table "users", :force => true do |t|
17
+ t.string "username"
18
+ t.string "password_hash"
19
+ t.datetime "created_at", :null => false
20
+ t.datetime "updated_at", :null => false
21
+ end
22
+
23
+ end
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ module OpenStax
4
+ module Utilities
5
+
6
+ describe AccessPolicy do
7
+
8
+ let!(:user) { User.create }
9
+
10
+ it 'responds to any _allowed? calls' do
11
+ AccessPolicy.register(User, DummyAccessPolicy)
12
+
13
+ DummyAccessPolicy.last_action = nil
14
+ DummyAccessPolicy.last_requestor = nil
15
+ DummyAccessPolicy.last_resource = nil
16
+
17
+ expect(AccessPolicy.respond_to? :wacky_allowed?).to eq(true)
18
+ expect(AccessPolicy.wacky_allowed?(user, user)).to eq(true)
19
+
20
+ expect(DummyAccessPolicy.last_action).to eq(:wacky)
21
+ expect(DummyAccessPolicy.last_requestor).to eq(user)
22
+ expect(DummyAccessPolicy.last_resource).to eq(user)
23
+ end
24
+
25
+ it 'delegates checks to policy classes based on resource class' do
26
+ dummy_object = double('Dummy')
27
+ dummy_policy = double('Dummy Policy', :action_allowed? => true)
28
+
29
+ AccessPolicy.register(User, DummyAccessPolicy)
30
+ AccessPolicy.register(dummy_object.class, dummy_policy)
31
+
32
+ DummyAccessPolicy.last_action = nil
33
+ DummyAccessPolicy.last_requestor = nil
34
+ DummyAccessPolicy.last_resource = nil
35
+
36
+ expect(AccessPolicy.action_allowed?(:read, user, dummy_object)).to(
37
+ eq(true))
38
+
39
+ expect{AccessPolicy.require_action_allowed!(:read, user, dummy_object)
40
+ }.not_to raise_error
41
+
42
+ expect(DummyAccessPolicy.last_action).to be_nil
43
+ expect(DummyAccessPolicy.last_requestor).to be_nil
44
+ expect(DummyAccessPolicy.last_resource).to be_nil
45
+
46
+ expect(AccessPolicy.action_allowed?(:create, user, User.new)).to(
47
+ eq(true))
48
+
49
+ expect{AccessPolicy.require_action_allowed!(:create, user, User.new)
50
+ }.not_to raise_error
51
+
52
+ expect(DummyAccessPolicy.last_action).to eq(:create)
53
+ expect(DummyAccessPolicy.last_requestor).to eq(user)
54
+ expect(DummyAccessPolicy.last_resource).to be_instance_of(User)
55
+ expect(DummyAccessPolicy.last_resource.id).to be_nil
56
+ end
57
+
58
+ it 'denies permission if the policy class is not registered' do
59
+ expect(OSU::AccessPolicy.action_allowed?(:destroy, user, Object)).to eq(false)
60
+
61
+ expect{OSU::AccessPolicy.require_action_allowed!(:destroy, user, Object)}.to raise_error(SecurityTransgression)
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+ end