express_access 1.0.0.a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +87 -0
  3. data/Rakefile +34 -0
  4. data/app/assets/javascripts/express_access/admin.js +1 -0
  5. data/app/assets/stylesheets/express_access/admin.css +5 -0
  6. data/app/assets/stylesheets/express_access/application.css +15 -0
  7. data/app/assets/stylesheets/express_access/main.sass +3 -0
  8. data/app/assets/stylesheets/express_access/sections/_role_dashboard.sass +29 -0
  9. data/app/assets/stylesheets/express_access.css +4 -0
  10. data/app/controllers/express_access/permissions_controller.rb +4 -0
  11. data/app/controllers/express_access/roles_controller.rb +14 -0
  12. data/app/controllers/express_access/routes_controller.rb +30 -0
  13. data/app/controllers/express_access/users_controller.rb +21 -0
  14. data/app/helpers/express_access/application_helper.rb +4 -0
  15. data/app/helpers/express_access/permissions_helper.rb +4 -0
  16. data/app/helpers/express_access/roles_helper.rb +4 -0
  17. data/app/models/express_access/audit_log.rb +27 -0
  18. data/app/models/express_access/permission.rb +130 -0
  19. data/app/models/express_access/role.rb +75 -0
  20. data/app/models/express_access/role_permission.rb +6 -0
  21. data/app/models/express_access/user_permission.rb +7 -0
  22. data/app/models/express_access/user_role.rb +7 -0
  23. data/app/views/express_access/permissions/index.html.et +13 -0
  24. data/app/views/express_access/permissions/show.html.et +33 -0
  25. data/app/views/express_access/roles/index.html.et +9 -0
  26. data/app/views/express_access/roles/show.html.et +68 -0
  27. data/app/views/express_access/routes/index.html.et +20 -0
  28. data/app/views/express_access/routes/show.html.et +46 -0
  29. data/app/views/express_access/users/index.html.et +26 -0
  30. data/app/views/express_access/users/show.html.et +55 -0
  31. data/app/views/layouts/express_access/admin.html.et +1 -0
  32. data/app/views/layouts/express_access/application.html.erb +14 -0
  33. data/config/initializers/mount_engine.rb +3 -0
  34. data/config/menu.yml +18 -0
  35. data/config/routes.rb +6 -0
  36. data/db/migrate/20141029223053_create_express_access_roles.rb +10 -0
  37. data/db/migrate/20141029223158_create_express_access_permissions.rb +9 -0
  38. data/db/migrate/20141029223233_create_express_access_role_permissions.rb +10 -0
  39. data/db/migrate/20141029223250_create_express_access_user_permissions.rb +10 -0
  40. data/db/migrate/20150528222337_create_express_access_user_roles.rb +9 -0
  41. data/db/migrate/20150609124815_add_description_to_role.rb +5 -0
  42. data/db/migrate/20150914023030_create_express_access_audit_logs.rb +15 -0
  43. data/db/migrate/20150921063153_add_after_sign_in_path_to_role.rb +5 -0
  44. data/lib/express_access/after_sign_in_filter.rb +7 -0
  45. data/lib/express_access/authorization_filter.rb +39 -0
  46. data/lib/express_access/engine.rb +12 -0
  47. data/lib/express_access/route.rb +127 -0
  48. data/lib/express_access/user.rb +79 -0
  49. data/lib/express_access/version.rb +3 -0
  50. data/lib/express_access.rb +51 -0
  51. data/lib/generators/express_access/install/USAGE +8 -0
  52. data/lib/generators/express_access/install/install_generator.rb +10 -0
  53. data/lib/tasks/express_access_tasks.rake +4 -0
  54. data/test/dummy/README.rdoc +28 -0
  55. data/test/dummy/Rakefile +6 -0
  56. data/test/dummy/app/assets/javascripts/application.js +13 -0
  57. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  58. data/test/dummy/app/controllers/application_controller.rb +5 -0
  59. data/test/dummy/app/controllers/posts_controller.rb +4 -0
  60. data/test/dummy/app/helpers/application_helper.rb +2 -0
  61. data/test/dummy/app/models/user.rb +9 -0
  62. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  63. data/test/dummy/app/views/posts/index.html.erb +0 -0
  64. data/test/dummy/bin/bundle +3 -0
  65. data/test/dummy/bin/rails +4 -0
  66. data/test/dummy/bin/rake +4 -0
  67. data/test/dummy/config/application.rb +25 -0
  68. data/test/dummy/config/boot.rb +5 -0
  69. data/test/dummy/config/database.yml +25 -0
  70. data/test/dummy/config/environment.rb +5 -0
  71. data/test/dummy/config/environments/development.rb +37 -0
  72. data/test/dummy/config/environments/production.rb +83 -0
  73. data/test/dummy/config/environments/test.rb +41 -0
  74. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  75. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  76. data/test/dummy/config/initializers/devise.rb +259 -0
  77. data/test/dummy/config/initializers/express_access.rb +1 -0
  78. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  79. data/test/dummy/config/initializers/inflections.rb +16 -0
  80. data/test/dummy/config/initializers/mime_types.rb +4 -0
  81. data/test/dummy/config/initializers/session_store.rb +3 -0
  82. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  83. data/test/dummy/config/locales/devise.en.yml +60 -0
  84. data/test/dummy/config/locales/en.yml +23 -0
  85. data/test/dummy/config/routes.rb +7 -0
  86. data/test/dummy/config/secrets.yml +22 -0
  87. data/test/dummy/config.ru +4 -0
  88. data/test/dummy/db/migrate/20150525001419_devise_create_users.rb +42 -0
  89. data/test/dummy/db/schema.rb +82 -0
  90. data/test/dummy/public/404.html +67 -0
  91. data/test/dummy/public/422.html +67 -0
  92. data/test/dummy/public/500.html +66 -0
  93. data/test/dummy/public/favicon.ico +0 -0
  94. data/test/dummy/test/fixtures/express_access/permissions.yml +28 -0
  95. data/test/dummy/test/fixtures/express_access/role_permissions.yml +21 -0
  96. data/test/dummy/test/fixtures/express_access/roles.yml +27 -0
  97. data/test/dummy/test/fixtures/express_access/user_permissions.yml +5 -0
  98. data/test/dummy/test/fixtures/express_access/user_roles.yml +15 -0
  99. data/test/dummy/test/fixtures/users.yml +19 -0
  100. data/test/dummy/test/initializer_test.rb +8 -0
  101. data/test/dummy/test/models/user_test.rb +7 -0
  102. data/test/express_access_test.rb +7 -0
  103. data/test/fixtures/express_access/audit_logs.yml +10 -0
  104. data/test/fixtures/express_access/permissions.yml +28 -0
  105. data/test/fixtures/express_access/role_permissions.yml +21 -0
  106. data/test/fixtures/express_access/roles.yml +34 -0
  107. data/test/fixtures/express_access/user_permissions.yml +5 -0
  108. data/test/fixtures/express_access/user_roles.yml +19 -0
  109. data/test/fixtures/users.yml +22 -0
  110. data/test/helpers/express_access/permissions_helper_test.rb +6 -0
  111. data/test/helpers/express_access/roles_helper_test.rb +6 -0
  112. data/test/integration/navigation_test.rb +33 -0
  113. data/test/lib/authorization_filter_test.rb +64 -0
  114. data/test/lib/generators/express_access/install/install_generator_test.rb +16 -0
  115. data/test/models/express_access/audit_log_test.rb +9 -0
  116. data/test/models/express_access/permission_test.rb +50 -0
  117. data/test/models/express_access/role_permission_test.rb +9 -0
  118. data/test/models/express_access/role_test.rb +36 -0
  119. data/test/models/express_access/user_permission_test.rb +9 -0
  120. data/test/models/express_access/user_role_test.rb +9 -0
  121. data/test/models/express_access/user_test.rb +77 -0
  122. data/test/test_helper.rb +19 -0
  123. metadata +375 -0
@@ -0,0 +1,34 @@
1
+ DEFAULTS: &DEFAULTS
2
+ created_at: <%= Time.now %>
3
+ updated_at: <%= Time.now %>
4
+
5
+ author:
6
+ name: Author
7
+ parent:
8
+ description: An author -- someone who writes.
9
+ after_sign_in_path: "/posts"
10
+ <<: *DEFAULTS
11
+
12
+ editor:
13
+ name: Editor
14
+ parent: author
15
+ description: Editor - someone who edits.
16
+ <<: *DEFAULTS
17
+
18
+ publisher:
19
+ name: Publisher
20
+ parent: author
21
+ description: Publishers - someone who publishes.
22
+ <<: *DEFAULTS
23
+
24
+ admin:
25
+ name: Admin
26
+ parent: publisher
27
+ description: Keys to the kingdom.
28
+ <<: *DEFAULTS
29
+
30
+ expresser:
31
+ name: Expresser
32
+ parent:
33
+ description: Expresser - someone who manages an appexpress site
34
+ <<: *DEFAULTS
@@ -0,0 +1,5 @@
1
+ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2
+
3
+ editor_specific:
4
+ user: editor
5
+ permission: user_specific_permission
@@ -0,0 +1,19 @@
1
+ admin_admin:
2
+ user: admin
3
+ role: admin
4
+
5
+ author_author:
6
+ user: author
7
+ role: author
8
+
9
+ editor_editor:
10
+ user: editor
11
+ role: editor
12
+
13
+ publisher_publisher:
14
+ user: publisher
15
+ role: publisher
16
+
17
+ expresser_expresser:
18
+ user: expresser
19
+ role: expresser
@@ -0,0 +1,22 @@
1
+ admin:
2
+ email: admin@example.com
3
+ encrypted_password: "$2a$10$3HSyBlfJ2zY3GPxEe1MmC.N8MKsSNYxv/lQR5yEW/ZsCKEzEjU/Vm"
4
+
5
+ author:
6
+ email: author@example.com
7
+ encrypted_password: "$2a$10$3HSyBlfJ2zY3GPxEe1MmC.N8MKsSNYxv/lQR5yEW/ZsCKEzEjU/Vm"
8
+
9
+ editor:
10
+ email: editor@example.com
11
+ encrypted_password: "$2a$10$3HSyBlfJ2zY3GPxEe1MmC.N8MKsSNYxv/lQR5yEW/ZsCKEzEjU/Vm"
12
+
13
+ publisher:
14
+ email: publisher@example.com
15
+ encrypted_password: "$2a$10$3HSyBlfJ2zY3GPxEe1MmC.N8MKsSNYxv/lQR5yEW/ZsCKEzEjU/Vm"
16
+
17
+ nobody:
18
+ email: nobody@example.com
19
+ encrypted_password: "$2a$10$3HSyBlfJ2zY3GPxEe1MmC.N8MKsSNYxv/lQR5yEW/ZsCKEzEjU/Vm"
20
+
21
+ expresser:
22
+ email: expresser@example.com
@@ -0,0 +1,6 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class PermissionsHelperTest < ActionView::TestCase
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class RolesHelperTest < ActionView::TestCase
5
+ end
6
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class NavigationTest < ActionDispatch::IntegrationTest
4
+ fixtures :all
5
+
6
+ test "redirect to login if not logged in" do
7
+ get '/posts'
8
+ assert_redirected_to new_user_session_path
9
+ end
10
+
11
+ test 'current user sees posts if they have permission' do
12
+ post_via_redirect user_session_path,
13
+ "user[email]" => 'editor@example.com',
14
+ "user[password]" => 'asdfasdf'
15
+ assert_equal "/", path
16
+ get '/posts'
17
+ assert_response :success
18
+ end
19
+
20
+ test "current user is redirected to the after_sign_in_path" do
21
+ post_via_redirect user_session_path,
22
+ "user[email]" => "author@example.com",
23
+ "user[password]" => "asdfasdf"
24
+ assert_equal "/posts", path
25
+ end
26
+
27
+ test "current user is redirected to the root_path if user's after_sign_in_path is nil" do
28
+ post_via_redirect user_session_path,
29
+ "user[email]" => "editor@example.com",
30
+ "user[password]" => "asdfasdf"
31
+ assert_equal "/", path
32
+ end
33
+ end
@@ -0,0 +1,64 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class AuthorizationFilterTest < ActiveSupport::TestCase
5
+ def setup
6
+ ExpressAccess.initialize_user!
7
+ end
8
+
9
+ def controller(controller, action, path, user)
10
+ OpenStruct.new( request: OpenStruct.new(
11
+ params: {
12
+ controller: controller,
13
+ action: action,
14
+ path: path
15
+ },
16
+ env: '123.123.123.123'
17
+ ),
18
+ current_user: user.nil? ? nil : users(user),
19
+ "access_authorization_failed!" => nil,
20
+ "authenticate_user!" => nil,
21
+ )
22
+ end
23
+
24
+ test 'if controller has current user and if current user has permission' do
25
+ assert_nil ExpressAccess::AuthorizationFilter.before(controller("posts", "edit", "posts/1/edit", :editor))
26
+ end
27
+
28
+ test 'if controller has current user and if current user has no permission' do
29
+ mock_obj = Minitest::Mock.new
30
+ mock_obj.expect(:call, nil)
31
+ c = controller("admin", "index", "admin", :editor)
32
+ c.stub(:access_authorization_failed!, mock_obj) do
33
+ ExpressAccess::AuthorizationFilter.before(c)
34
+ end
35
+ mock_obj.verify
36
+ end
37
+
38
+ test 'if controller has no current user and Devise is not defined' do
39
+ TempDevise = Devise
40
+ Object.send(:remove_const, :Devise)
41
+ assert_nil defined?(Devise)
42
+ mock_obj = Minitest::Mock.new
43
+ mock_obj.expect(:call, nil)
44
+ c = controller("admin", "index", "admin", :editor)
45
+ c.stub(:access_authorization_failed!, mock_obj) do
46
+ ExpressAccess::AuthorizationFilter.before(c)
47
+ end
48
+ mock_obj.verify
49
+ ::Devise = TempDevise
50
+ assert_equal 'constant', defined?(Devise)
51
+ end
52
+
53
+ test 'if controller has no current user and Devise is defined' do
54
+ assert_equal 'constant', defined?(Devise)
55
+ mock_obj = Minitest::Mock.new
56
+ mock_obj.expect(:call, nil)
57
+ c = controller("admin", "index", "admin", nil)
58
+ c.stub(:authenticate_user!, mock_obj) do
59
+ ExpressAccess::AuthorizationFilter.before(c)
60
+ end
61
+ mock_obj.verify
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,16 @@
1
+ require 'test_helper'
2
+ require 'generators/express_access/install/install_generator'
3
+
4
+ module ExpressAccess
5
+ class ExpressAccess::InstallGeneratorTest < Rails::Generators::TestCase
6
+ tests ExpressAccess::InstallGenerator
7
+ destination Rails.root.join('tmp/generators')
8
+ setup :prepare_destination
9
+
10
+ # test "generator runs without errors" do
11
+ # assert_nothing_raised do
12
+ # run_generator ["arguments"]
13
+ # end
14
+ # end
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class AuditLogTest < ActiveSupport::TestCase
5
+ # test "the truth" do
6
+ # assert true
7
+ # end
8
+ end
9
+ end
@@ -0,0 +1,50 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class PermissionTest < ActiveSupport::TestCase
5
+
6
+ test "Permission.[] looks up permissions" do
7
+ assert Permission[:admin]
8
+ end
9
+
10
+ # test '.for returns the most specific applicable permission'
11
+
12
+ def assert_permission(name, is_for: [])
13
+ named_args = {controller: is_for[0], action: is_for[1], path: is_for[2]}
14
+ assert_equal Permission[name].name, Permission.for(**named_args).try(:name)
15
+ end
16
+
17
+ test 'controller#action specific permissions have priority' do
18
+ assert_permission 'posts#edit', is_for: ['posts', 'edit', '/admin/posts/123/edit']
19
+ assert_permission 'posts#edit', is_for: ['posts', 'edit', '/posts/123/edit']
20
+ assert_permission 'posts#edit', is_for: ['posts', 'edit', 'askdjfklasdfhjk']
21
+
22
+ assert_permission 'posts#publish', is_for: ['posts', 'publish', '/admin/posts/123/publish']
23
+ end
24
+
25
+ test 'resource permission overrides controller#action when path is longer' do
26
+ assert_permission '/posts/999', is_for: ['posts', 'publish', '/posts/999/publish']
27
+ end
28
+
29
+ test 'bare controller permission protects a controller regardless of path' do
30
+ assert_permission 'posts', is_for: ['posts', 'show', '/admin/posts/123']
31
+ assert_permission 'posts', is_for: ['posts', 'whatever', nil]
32
+ assert_permission 'posts', is_for: ['posts', 'index', '/']
33
+ end
34
+
35
+ test 'locked parent path locks sub paths' do
36
+ assert_permission '/accounting', is_for: ['invoices', 'index', '/accounting/invoices']
37
+ assert_permission '/accounting', is_for: ['invoices', 'create', '/accounting/invoices']
38
+ end
39
+
40
+ test 'sub path permission takes precedence over parent path permission' do
41
+ assert_permission '/accounting/gl', is_for: ['gl/entry', 'index', '/accounting/gl/entries']
42
+ assert_permission '/accounting/gl', is_for: ['gl/entry', 'create', '/accounting/gl/entries']
43
+ end
44
+
45
+
46
+ test ".for returns nil for requests that have no applicable permission" do
47
+ assert_nil Permission.for(controller: 'jhasdkfjgha', action: 'index', path: '/asdfkgnqe/')
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class RolePermissionTest < ActiveSupport::TestCase
5
+ # test "the truth" do
6
+ # assert true
7
+ # end
8
+ end
9
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class RoleTest < ActiveSupport::TestCase
5
+
6
+ test "there are 5 roles" do
7
+ assert_equal 5, Role.count
8
+ end
9
+
10
+ test "#expressers return users with role of expresser" do
11
+ assert_equal 1, Role.expressers.count
12
+ end
13
+
14
+ test "parent relationships are set properly" do
15
+ assert_equal Role[:author], Role[:editor].parent
16
+ assert_equal Role[:author], Role[:publisher].parent
17
+ end
18
+
19
+ test "top_level scope identifies roles without a parent" do
20
+ [Role[:expresser], Role[:author]].each do |role|
21
+ assert_includes Role.top_level, role
22
+ end
23
+ end
24
+
25
+ test "roles have permissions" do
26
+ assert_includes Role[:author].permissions, Permission[:posts]
27
+ assert_not_includes Role[:author].permissions, Permission[:posts_edit]
28
+ assert_includes Role[:editor].permissions, Permission[:"posts#edit"]
29
+ end
30
+
31
+ test "roles inherit permissions from parent roles" do
32
+ assert_includes Role[:editor].permissions, Permission[:posts]
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class UserPermissionTest < ActiveSupport::TestCase
5
+ # test "the truth" do
6
+ # assert true
7
+ # end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class UserRoleTest < ActiveSupport::TestCase
5
+ # test "the truth" do
6
+ # assert true
7
+ # end
8
+ end
9
+ end
@@ -0,0 +1,77 @@
1
+ require 'test_helper'
2
+
3
+ module ExpressAccess
4
+ class UserTest < ActiveSupport::TestCase
5
+
6
+ setup do
7
+ ExpressAccess.initialize_user!
8
+ end
9
+
10
+ test "ExpressAccess::User included in ::User" do
11
+ assert_includes ::User.ancestors, ExpressAccess::User
12
+ end
13
+
14
+ test "user has direct permissions" do
15
+ assert_includes users(:editor).direct_permissions, Permission[:something_special]
16
+ end
17
+
18
+ test "user permissions include direct_permissions" do
19
+ assert users(:editor).direct_permissions.to_set <= users(:editor).permissions
20
+ end
21
+
22
+ test "#may? is true if a user has that permission" do
23
+ assert users(:editor).may?(:something_special)
24
+ assert users(:editor).may_do?(:something_special)
25
+ end
26
+
27
+ test "user has roles" do
28
+ assert users(:editor).roles.includes(Role[:editor])
29
+ end
30
+
31
+ test "user has permissions through role" do
32
+ assert users(:editor).may_do?("posts#edit")
33
+ end
34
+
35
+ test "user permissions includes role and direct permissions" do
36
+ assert users(:editor).direct_permissions.to_set <= users(:editor).permissions
37
+ assert users(:editor).role_permissions.to_set <= users(:editor).permissions
38
+ end
39
+
40
+ test "user provides sexy method_missing dsl" do
41
+ assert users(:editor).may_edit?(:posts)
42
+ end
43
+
44
+ # that which is not forbidden is permitted
45
+ test "user may do something if no such permission exists" do
46
+ assert users(:editor).may_destroy?(:posts)
47
+ end
48
+
49
+ test "user may not do something if they do not have permission" do
50
+ assert_not users(:nobody).may_edit?(:posts)
51
+ end
52
+
53
+ test "user can be assigned direct_permissions" do
54
+ refute users(:author).may_do?(:something_special)
55
+ users(:author).direct_permission_ids = [Permission[:something_special].id]
56
+ assert users(:author).may_do?(:something_special)
57
+ end
58
+
59
+ test "#after_sign_in_path retrieves after_sign_in_path from roles" do
60
+ author = users(:author)
61
+
62
+ assert_equal "/posts", author.after_sign_in_path
63
+ end
64
+
65
+ test "#after_sign_in_path returns nil if any of the user's roles don't have #after_sign_in_path value" do
66
+ editor = users(:editor)
67
+
68
+ assert_nil editor.after_sign_in_path
69
+ end
70
+
71
+ test "#after_sign_in_path returns nil if user has no roles" do
72
+ nobody = users(:nobody)
73
+
74
+ assert_nil nobody.after_sign_in_path
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,19 @@
1
+ # Configure Rails Environment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rails/test_help"
6
+ require 'minitest/rg'
7
+ require 'minitest/mock'
8
+ require 'pry'
9
+
10
+ Rails.backtrace_cleaner.remove_silencers!
11
+
12
+ # Load support files
13
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
14
+
15
+
16
+ if ActiveSupport::TestCase.respond_to?(:fixture_path=)
17
+ ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
18
+ ActiveSupport::TestCase.fixtures :all
19
+ end