workarea-basic_auth 1.1.1

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 (77) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  4. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.gitignore +25 -0
  7. data/CHANGELOG.md +371 -0
  8. data/CODE_OF_CONDUCT.md +3 -0
  9. data/CONTRIBUTING.md +3 -0
  10. data/Gemfile +5 -0
  11. data/LICENSE +52 -0
  12. data/README.md +105 -0
  13. data/Rakefile +60 -0
  14. data/bin/rails +20 -0
  15. data/config/initializers/access_control.rb +23 -0
  16. data/lib/tasks/basic_auth_tasks.rake +4 -0
  17. data/lib/workarea/basic_auth.rb +23 -0
  18. data/lib/workarea/basic_auth/engine.rb +8 -0
  19. data/lib/workarea/basic_auth/middleware.rb +82 -0
  20. data/lib/workarea/basic_auth/path.rb +37 -0
  21. data/lib/workarea/basic_auth/railtie.rb +16 -0
  22. data/lib/workarea/basic_auth/simple_route_set.rb +23 -0
  23. data/lib/workarea/basic_auth/version.rb +5 -0
  24. data/test/dummy/Rakefile +6 -0
  25. data/test/dummy/app/assets/config/manifest.js +4 -0
  26. data/test/dummy/app/assets/images/.keep +0 -0
  27. data/test/dummy/app/assets/javascripts/application.js +13 -0
  28. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  29. data/test/dummy/app/controllers/application_controller.rb +3 -0
  30. data/test/dummy/app/controllers/concerns/.keep +0 -0
  31. data/test/dummy/app/helpers/application_helper.rb +2 -0
  32. data/test/dummy/app/jobs/application_job.rb +2 -0
  33. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  34. data/test/dummy/app/models/concerns/.keep +0 -0
  35. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  36. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  37. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  38. data/test/dummy/bin/bundle +3 -0
  39. data/test/dummy/bin/rails +4 -0
  40. data/test/dummy/bin/rake +4 -0
  41. data/test/dummy/bin/setup +34 -0
  42. data/test/dummy/bin/update +29 -0
  43. data/test/dummy/config.ru +5 -0
  44. data/test/dummy/config/application.rb +17 -0
  45. data/test/dummy/config/boot.rb +5 -0
  46. data/test/dummy/config/cable.yml +9 -0
  47. data/test/dummy/config/environment.rb +5 -0
  48. data/test/dummy/config/environments/development.rb +56 -0
  49. data/test/dummy/config/environments/production.rb +86 -0
  50. data/test/dummy/config/environments/test.rb +43 -0
  51. data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
  52. data/test/dummy/config/initializers/assets.rb +11 -0
  53. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  54. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  55. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  56. data/test/dummy/config/initializers/inflections.rb +16 -0
  57. data/test/dummy/config/initializers/mime_types.rb +4 -0
  58. data/test/dummy/config/initializers/new_framework_defaults.rb +21 -0
  59. data/test/dummy/config/initializers/session_store.rb +3 -0
  60. data/test/dummy/config/initializers/workarea.rb +4 -0
  61. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  62. data/test/dummy/config/locales/en.yml +23 -0
  63. data/test/dummy/config/puma.rb +47 -0
  64. data/test/dummy/config/routes.rb +5 -0
  65. data/test/dummy/config/secrets.yml +22 -0
  66. data/test/dummy/config/spring.rb +6 -0
  67. data/test/dummy/db/seeds.rb +2 -0
  68. data/test/dummy/lib/assets/.keep +0 -0
  69. data/test/dummy/log/.keep +0 -0
  70. data/test/factories/workarea/testing/basic_auth_helper.rb +21 -0
  71. data/test/lib/workarea/basic_auth/middleware_test.rb +149 -0
  72. data/test/lib/workarea/basic_auth/path_test.rb +50 -0
  73. data/test/lib/workarea/basic_auth/simple_route_set_test.rb +64 -0
  74. data/test/lib/workarea/basic_auth_test.rb +12 -0
  75. data/test/test_helper.rb +9 -0
  76. data/workarea-basic_auth.gemspec +39 -0
  77. metadata +226 -0
@@ -0,0 +1,6 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # ApplicationController.renderer.defaults.merge!(
4
+ # http_host: 'example.org',
5
+ # https: false
6
+ # )
@@ -0,0 +1,11 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Version of your assets, change this if you want to expire all your assets.
4
+ Rails.application.config.assets.version = "1.0"
5
+
6
+ # Add additional assets to the asset load path
7
+ # Rails.application.config.assets.paths << Emoji.images_path
8
+
9
+ # Precompile additional assets.
10
+ # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11
+ # Rails.application.config.assets.precompile += %w( search.js )
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4
+ # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5
+
6
+ # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7
+ # Rails.backtrace_cleaner.remove_silencers!
@@ -0,0 +1,5 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Specify a serializer for the signed and encrypted cookie jars.
4
+ # Valid options are :json, :marshal, and :hybrid.
5
+ Rails.application.config.action_dispatch.cookies_serializer = :json
@@ -0,0 +1,4 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Configure sensitive parameters which will be filtered from the log file.
4
+ Rails.application.config.filter_parameters += [:password]
@@ -0,0 +1,16 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new inflection rules using the following format. Inflections
4
+ # are locale specific, and you may define rules for as many different
5
+ # locales as you wish. All of these examples are active by default:
6
+ # ActiveSupport::Inflector.inflections(:en) do |inflect|
7
+ # inflect.plural /^(ox)$/i, '\1en'
8
+ # inflect.singular /^(ox)en/i, '\1'
9
+ # inflect.irregular 'person', 'people'
10
+ # inflect.uncountable %w( fish sheep )
11
+ # end
12
+
13
+ # These inflection rules are supported but not enabled by default:
14
+ # ActiveSupport::Inflector.inflections(:en) do |inflect|
15
+ # inflect.acronym 'RESTful'
16
+ # end
@@ -0,0 +1,4 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new mime types for use in respond_to blocks:
4
+ # Mime::Type.register "text/richtext", :rtf
@@ -0,0 +1,21 @@
1
+ # Be sure to restart your server when you modify this file.
2
+ #
3
+ # This file contains migration options to ease your Rails 5.0 upgrade.
4
+ #
5
+ # Read the Guide for Upgrading Ruby on Rails for more info on each option.
6
+
7
+ # Enable per-form CSRF tokens. Previous versions had false.
8
+ Rails.application.config.action_controller.per_form_csrf_tokens = true
9
+
10
+ # Enable origin-checking CSRF mitigation. Previous versions had false.
11
+ Rails.application.config.action_controller.forgery_protection_origin_check = true
12
+
13
+ # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`.
14
+ # Previous versions had false.
15
+ ActiveSupport.to_time_preserves_timezone = true
16
+
17
+ # Require `belongs_to` associations by default. Previous versions had false.
18
+ # Rails.application.config.active_record.belongs_to_required_by_default = true
19
+
20
+ # Configure SSL options to enable HSTS with subdomains. Previous versions had false.
21
+ Rails.application.config.ssl_options = { hsts: { subdomains: true } }
@@ -0,0 +1,3 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ Rails.application.config.session_store :cookie_store, key: "_dummy_session"
@@ -0,0 +1,4 @@
1
+ Workarea.configure do |config|
2
+ # Basic site info
3
+ config.site_name = "WebLinc Basic Auth"
4
+ end
@@ -0,0 +1,14 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # This file contains settings for ActionController::ParamsWrapper which
4
+ # is enabled by default.
5
+
6
+ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7
+ ActiveSupport.on_load(:action_controller) do
8
+ wrap_parameters format: [:json]
9
+ end
10
+
11
+ # To enable root element in JSON for ActiveRecord objects.
12
+ # ActiveSupport.on_load(:active_record) do
13
+ # self.include_root_in_json = true
14
+ # end
@@ -0,0 +1,23 @@
1
+ # Files in the config/locales directory are used for internationalization
2
+ # and are automatically loaded by Rails. If you want to use locales other
3
+ # than English, add the necessary files in this directory.
4
+ #
5
+ # To use the locales, use `I18n.t`:
6
+ #
7
+ # I18n.t 'hello'
8
+ #
9
+ # In views, this is aliased to just `t`:
10
+ #
11
+ # <%= t('hello') %>
12
+ #
13
+ # To use a different locale, set it with `I18n.locale`:
14
+ #
15
+ # I18n.locale = :es
16
+ #
17
+ # This would use the information in config/locales/es.yml.
18
+ #
19
+ # To learn more, please read the Rails Internationalization guide
20
+ # available at http://guides.rubyonrails.org/i18n.html.
21
+
22
+ en:
23
+ hello: "Hello world"
@@ -0,0 +1,47 @@
1
+ # Puma can serve each request in a thread from an internal thread pool.
2
+ # The `threads` method setting takes two numbers a minimum and maximum.
3
+ # Any libraries that use thread pools should be configured to match
4
+ # the maximum value specified for Puma. Default is set to 5 threads for minimum
5
+ # and maximum, this matches the default thread size of Active Record.
6
+ #
7
+ threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
8
+ threads threads_count, threads_count
9
+
10
+ # Specifies the `port` that Puma will listen on to receive requests, default is 3000.
11
+ #
12
+ port ENV.fetch("PORT") { 3000 }
13
+
14
+ # Specifies the `environment` that Puma will run in.
15
+ #
16
+ environment ENV.fetch("RAILS_ENV") { "development" }
17
+
18
+ # Specifies the number of `workers` to boot in clustered mode.
19
+ # Workers are forked webserver processes. If using threads and workers together
20
+ # the concurrency of the application would be max `threads` * `workers`.
21
+ # Workers do not work on JRuby or Windows (both of which do not support
22
+ # processes).
23
+ #
24
+ # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
25
+
26
+ # Use the `preload_app!` method when specifying a `workers` number.
27
+ # This directive tells Puma to first boot the application and load code
28
+ # before forking the application. This takes advantage of Copy On Write
29
+ # process behavior so workers use less memory. If you use this option
30
+ # you need to make sure to reconnect any threads in the `on_worker_boot`
31
+ # block.
32
+ #
33
+ # preload_app!
34
+
35
+ # The code in the `on_worker_boot` will be called if you are using
36
+ # clustered mode by specifying a number of `workers`. After each worker
37
+ # process is booted this block will be run, if you are using `preload_app!`
38
+ # option you will want to use this block to reconnect to any threads
39
+ # or connections that may have been created at application boot, Ruby
40
+ # cannot share connections between processes.
41
+ #
42
+ # on_worker_boot do
43
+ # ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
44
+ # end
45
+
46
+ # Allow puma to be restarted by `rails restart` command.
47
+ plugin :tmp_restart
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ mount Workarea::Core::Engine => "/"
3
+ mount Workarea::Admin::Engine => "/admin", as: "admin"
4
+ mount Workarea::Storefront::Engine => "/", as: "storefront"
5
+ end
@@ -0,0 +1,22 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key is used for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+
6
+ # Make sure the secret is at least 30 characters and all random,
7
+ # no regular words or you'll be exposed to dictionary attacks.
8
+ # You can use `rails secret` to generate a secure secret key.
9
+
10
+ # Make sure the secrets in this file are kept private
11
+ # if you're sharing your code publicly.
12
+
13
+ development:
14
+ secret_key_base: e3136ca2a4ab2bb5ea181b14ff500ae40db8718fb990d590bfed3774247d430c805c45686322f93e8a746d034fa1fba9ef00a9ce7a35aee9339675ccb0426121
15
+
16
+ test:
17
+ secret_key_base: 8183e0351525142fce68cf619e94c68caa017c9b90c03183d288ee4a32283d77838eb94bc252e5159eabf3e20a77f8df9466b5056e14b59631dfa592b67e9bbd
18
+
19
+ # Do not keep production secrets in the repository,
20
+ # instead read values from the environment.
21
+ production:
22
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
@@ -0,0 +1,6 @@
1
+ %w(
2
+ .ruby-version
3
+ .rbenv-vars
4
+ tmp/restart.txt
5
+ tmp/caching-dev.txt
6
+ ).each { |path| Spring.watch(path) }
@@ -0,0 +1,2 @@
1
+ require "workarea/seeds"
2
+ Workarea::Seeds.run
File without changes
File without changes
@@ -0,0 +1,21 @@
1
+ module Workarea
2
+ module Testing
3
+ module BasicAuthHelper
4
+ def encode_password(username, password)
5
+ Base64.encode64("#{username}:#{password}")
6
+ end
7
+
8
+ def build_request(path, method = "GET")
9
+ Rack::Request.new(
10
+ Rack::MockRequest.env_for(path, "REQUEST_METHOD" => method)
11
+ )
12
+ end
13
+
14
+ def build_response(path, method = "GET")
15
+ Rack::Response.new(
16
+ Rack::MockRequest.env_for(path, "REQUEST_METHOD" => method)
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,149 @@
1
+ require "test_helper"
2
+
3
+ module Workarea
4
+ module BasicAuth
5
+ class MiddlewareTest < Workarea::TestCase
6
+ include Workarea::Testing::BasicAuthHelper
7
+
8
+ setup :turn_on_basic_auth
9
+ teardown :turn_off_basic_auth
10
+
11
+ def middleware
12
+ @middleware ||= BasicAuth::Middleware.new(Rails.application)
13
+ end
14
+
15
+ def turn_on_basic_auth
16
+ Workarea.config.basic_auth.enabled = true
17
+ Workarea.config.basic_auth.user = "thomas"
18
+ Workarea.config.basic_auth.pass = "vendetta"
19
+ Workarea.config.basic_auth.protect_routes = BasicAuth::SimpleRouteSet.new
20
+ Workarea.config.basic_auth.exclude_routes = BasicAuth::SimpleRouteSet.new
21
+ end
22
+
23
+ def turn_off_basic_auth
24
+ Workarea.config.basic_auth.enabled = false
25
+ end
26
+
27
+ def test_unathorized_users_doesnt_do_anything_if_basic_auth_is_disabled
28
+ Workarea.config.basic_auth.enabled = false
29
+
30
+ env = Rack::MockRequest.env_for("/")
31
+ response = Rack::Response.new(middleware.call(env))
32
+
33
+ assert_equal(200, response.status)
34
+ end
35
+
36
+ def test_unathorized_users_returns_200_if_route_is_unprotected
37
+ env = Rack::MockRequest.env_for("/login")
38
+ get_login = Rack::Response.new(middleware.call(env))
39
+
40
+ assert_equal(200, get_login.status)
41
+ end
42
+
43
+ def test_unauthorized_users_returns_200_if_ip_is_whitelisted
44
+ ip_addr = Workarea.config.basic_auth.whitelisted_ips.first.to_s
45
+ env = Rack::MockRequest.env_for("/login", 'REMOTE_ADDR' => ip_addr)
46
+ get_login = Rack::Response.new(middleware.call(env))
47
+
48
+ assert_equal(200, get_login.status)
49
+ end
50
+
51
+ def test_unathorized_users_returns_401_for_all_http_methods_on_a_path_by_default
52
+ Workarea.config.basic_auth.protect_routes.add("/login")
53
+
54
+ env = Rack::MockRequest.env_for("/login")
55
+ get_login = Rack::MockResponse.new(*middleware.call(env))
56
+
57
+ env = Rack::MockRequest.env_for("/login", method: :post)
58
+ post_login = Rack::MockResponse.new(*middleware.call(env))
59
+
60
+ env = Rack::MockRequest.env_for("/login", method: :head)
61
+ head_login = Rack::MockResponse.new(*middleware.call(env))
62
+
63
+ assert_equal(401, get_login.status)
64
+ assert_equal(401, post_login.status)
65
+ assert_equal(401, head_login.status)
66
+ end
67
+
68
+ def test_unathorized_users_returns_401_for_specific_http_methods_on_a_path
69
+ Workarea.config.basic_auth.protect_routes.add("/login", :post)
70
+
71
+ env = Rack::MockRequest.env_for("/login")
72
+ get_login = Rack::MockResponse.new(*middleware.call(env))
73
+
74
+ env = Rack::MockRequest.env_for("/login", method: :post)
75
+ post_login = Rack::MockResponse.new(*middleware.call(env))
76
+
77
+ assert_equal(200, get_login.status)
78
+ assert_equal(401, post_login.status)
79
+ end
80
+
81
+ def test_unathorized_users_protects_wildcard_routes
82
+ Workarea.config.basic_auth.protect_routes.add("/*")
83
+
84
+ env = Rack::MockRequest.env_for("/login")
85
+ get_login = Rack::MockResponse.new(*middleware.call(env))
86
+
87
+ env = Rack::MockRequest.env_for("/login", method: :post)
88
+ post_login = Rack::MockResponse.new(*middleware.call(env))
89
+
90
+ env = Rack::MockRequest.env_for("/products/my-product")
91
+ get_product = Rack::MockResponse.new(*middleware.call(env))
92
+
93
+ assert_equal(401, get_login.status)
94
+ assert_equal(401, post_login.status)
95
+ assert_equal(401, get_product.status)
96
+ end
97
+
98
+ def test_unathorized_users_allows_route_exclusions
99
+ Workarea.config.basic_auth.protect_routes.add("/*")
100
+ Workarea.config.basic_auth.exclude_routes.add("/contact")
101
+
102
+ env = Rack::MockRequest.env_for("/login")
103
+ get_login = Rack::MockResponse.new(*middleware.call(env))
104
+
105
+ env = Rack::MockRequest.env_for("/contact")
106
+ get_contact = Rack::MockResponse.new(*middleware.call(env))
107
+
108
+ assert_equal(401, get_login.status)
109
+ assert_equal(200, get_contact.status)
110
+ end
111
+
112
+ def test_unathorized_users_works_properly_with_a_health_check
113
+ Workarea.config.basic_auth.protect_routes.add("/*")
114
+ Workarea.config.basic_auth.exclude_routes.add("/health_check")
115
+
116
+ env = Rack::MockRequest.env_for("/health_check")
117
+ health_check = Rack::MockResponse.new(*middleware.call(env))
118
+
119
+ assert_equal(200, health_check.status)
120
+ end
121
+
122
+ def test_authorized_users_lets_authorized_users_access_all_routes
123
+ Workarea.config.basic_auth.protect_routes.add("/*")
124
+
125
+ env = Rack::MockRequest.env_for("/contact")
126
+ bad = Rack::MockResponse.new(*middleware.call(env))
127
+ assert_equal(401, bad.status)
128
+
129
+ encoded_pass = encode_password("thomas", "vendetta")
130
+ env_opts = { "HTTP_AUTHORIZATION" => "Basic #{encoded_pass}" }
131
+
132
+ env = Rack::MockRequest.env_for("/login", env_opts)
133
+ good = Rack::MockResponse.new(*middleware.call(env))
134
+ assert_equal(200, good.status)
135
+ end
136
+
137
+ def test_authorized_users_renders_401_with_invalid_credentials
138
+ Workarea.config.basic_auth.protect_routes.add("/*")
139
+
140
+ encoded_pass = encode_password("notavalid", "password")
141
+ env_opts = { "HTTP_AUTHORIZATION" => "Basic #{encoded_pass}" }
142
+
143
+ env = Rack::MockRequest.env_for("/contact", env_opts)
144
+ bad = Rack::MockResponse.new(*middleware.call(env))
145
+ assert_equal(401, bad.status)
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,50 @@
1
+ require "test_helper"
2
+ require "rack/mock"
3
+
4
+ module Workarea
5
+ module BasicAuth
6
+ class PathTest < Workarea::TestCase
7
+ include Workarea::Testing::BasicAuthHelper
8
+
9
+ def test_matches_a_pathname_and_all_http_methods_by_default
10
+ path = Path.new("/products")
11
+
12
+ get = build_request("/products")
13
+ post = build_request("/products", "POST")
14
+ options = build_request("/products", "OPTIONS")
15
+ head = build_request("/products", "HEAD")
16
+
17
+ bad = build_request("/wat")
18
+
19
+ assert path.matches?(get)
20
+ assert path.matches?(post)
21
+ assert path.matches?(options)
22
+ assert path.matches?(head)
23
+
24
+ refute path.matches?(bad)
25
+ end
26
+
27
+ def test_matches_a_pathname_and_a_specific_request_method
28
+ path = Path.new("/products", :post, :head)
29
+
30
+ get = build_request("/products")
31
+ post = build_request("/products", "POST")
32
+ head = build_request("/products", "HEAD")
33
+
34
+ refute path.matches?(get)
35
+ assert path.matches?(post)
36
+ assert path.matches?(head)
37
+ end
38
+
39
+ def test_matches_wildcards
40
+ path = Path.new("/api/v2/*")
41
+
42
+ good = build_request("/api/v2/wat/sup")
43
+ bad = build_request("/api/v1/wat/sup")
44
+
45
+ assert path.matches?(good)
46
+ refute path.matches?(bad)
47
+ end
48
+ end
49
+ end
50
+ end