workarea-basic_auth 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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