keycloak_rack 1.0.0
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.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +68 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.rubocop.yml +220 -0
- data/.ruby-version +1 -0
- data/.yardopts +7 -0
- data/Appraisals +16 -0
- data/CHANGELOG.md +10 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Gemfile +5 -0
- data/LICENSE +19 -0
- data/README.md +288 -0
- data/Rakefile +10 -0
- data/bin/appraisal +29 -0
- data/bin/console +6 -0
- data/bin/fix-appraisals +14 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/bin/yard +29 -0
- data/bin/yardoc +29 -0
- data/bin/yri +29 -0
- data/gemfiles/rack_only.gemfile +5 -0
- data/gemfiles/rack_only.gemfile.lock +204 -0
- data/gemfiles/rails_6_0.gemfile +9 -0
- data/gemfiles/rails_6_0.gemfile.lock +323 -0
- data/gemfiles/rails_6_1.gemfile +9 -0
- data/gemfiles/rails_6_1.gemfile.lock +326 -0
- data/keycloak_rack.gemspec +56 -0
- data/lib/keycloak_rack.rb +59 -0
- data/lib/keycloak_rack/authenticate.rb +115 -0
- data/lib/keycloak_rack/authorize_realm.rb +53 -0
- data/lib/keycloak_rack/authorize_resource.rb +54 -0
- data/lib/keycloak_rack/config.rb +84 -0
- data/lib/keycloak_rack/container.rb +53 -0
- data/lib/keycloak_rack/decoded_token.rb +191 -0
- data/lib/keycloak_rack/flexible_struct.rb +20 -0
- data/lib/keycloak_rack/http_client.rb +86 -0
- data/lib/keycloak_rack/import.rb +9 -0
- data/lib/keycloak_rack/key_fetcher.rb +20 -0
- data/lib/keycloak_rack/key_resolver.rb +64 -0
- data/lib/keycloak_rack/middleware.rb +132 -0
- data/lib/keycloak_rack/railtie.rb +14 -0
- data/lib/keycloak_rack/read_token.rb +40 -0
- data/lib/keycloak_rack/resource_role_map.rb +8 -0
- data/lib/keycloak_rack/role_map.rb +15 -0
- data/lib/keycloak_rack/session.rb +44 -0
- data/lib/keycloak_rack/skip_authentication.rb +44 -0
- data/lib/keycloak_rack/types.rb +42 -0
- data/lib/keycloak_rack/version.rb +6 -0
- data/lib/keycloak_rack/with_config.rb +15 -0
- data/spec/dummy/.ruby-version +1 -0
- data/spec/dummy/README.md +24 -0
- data/spec/dummy/Rakefile +8 -0
- data/spec/dummy/app/controllers/application_controller.rb +22 -0
- data/spec/dummy/app/controllers/test_controller.rb +9 -0
- data/spec/dummy/config.ru +8 -0
- data/spec/dummy/config/application.rb +52 -0
- data/spec/dummy/config/boot.rb +3 -0
- data/spec/dummy/config/environment.rb +7 -0
- data/spec/dummy/config/environments/development.rb +51 -0
- data/spec/dummy/config/environments/test.rb +51 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +9 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +10 -0
- data/spec/dummy/config/initializers/cors.rb +17 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +8 -0
- data/spec/dummy/config/initializers/inflections.rb +17 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
- data/spec/dummy/config/keycloak.yml +12 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/public/robots.txt +1 -0
- data/spec/dummy/tmp/development_secret.txt +1 -0
- data/spec/factories/decoded_token.rb +18 -0
- data/spec/factories/session.rb +21 -0
- data/spec/factories/token_payload.rb +40 -0
- data/spec/keycloak_rack/authorize_realm_spec.rb +15 -0
- data/spec/keycloak_rack/authorize_resource_spec.rb +19 -0
- data/spec/keycloak_rack/decoded_token_spec.rb +31 -0
- data/spec/keycloak_rack/key_resolver_spec.rb +95 -0
- data/spec/keycloak_rack/middleware_spec.rb +172 -0
- data/spec/keycloak_rack/rails_integration_spec.rb +43 -0
- data/spec/keycloak_rack/session_spec.rb +37 -0
- data/spec/keycloak_rack/skip_authentication_spec.rb +55 -0
- data/spec/spec_helper.rb +101 -0
- data/spec/support/contexts/mocked_keycloak.rb +63 -0
- data/spec/support/contexts/mocked_rack_application.rb +41 -0
- data/spec/support/test_key.pem +27 -0
- data/spec/support/token_helper.rb +76 -0
- metadata +616 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KeycloakRack
|
4
|
+
# Check if the request should be skipped based on the request method and path.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
# @!visibility private
|
8
|
+
class SkipAuthentication
|
9
|
+
include Dry::Monads[:result]
|
10
|
+
|
11
|
+
include Import[config: "keycloak-rack.config"]
|
12
|
+
|
13
|
+
delegate :skip_paths, to: :config
|
14
|
+
|
15
|
+
# @return [Dry::Monads::Success(Boolean)]
|
16
|
+
def call(env)
|
17
|
+
method = env["REQUEST_METHOD"].to_s.downcase
|
18
|
+
path = env["PATH_INFO"]
|
19
|
+
|
20
|
+
return Success(true) if preflight?(method, env)
|
21
|
+
return Success(true) if should_skip?(method, path)
|
22
|
+
|
23
|
+
Success(false)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def should_skip?(method, path)
|
29
|
+
method_paths = skip_paths.fetch(method, [])
|
30
|
+
|
31
|
+
method_paths.any? do |path_pattern|
|
32
|
+
if path_pattern.kind_of?(Regexp)
|
33
|
+
path_pattern.match? path
|
34
|
+
else
|
35
|
+
path_pattern == path
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def preflight?(method, headers)
|
41
|
+
method == "options" && headers["HTTP_ACCESS_CONTROL_REQUEST_METHOD"].present?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KeycloakRack
|
4
|
+
# dry-rb types for this gem.
|
5
|
+
#
|
6
|
+
# @see https://dry-rb.org/gems/dry-types
|
7
|
+
# @api private
|
8
|
+
# @!visibility private
|
9
|
+
module Types
|
10
|
+
include Dry.Types
|
11
|
+
|
12
|
+
# A type to make indifferent hashes
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
IndifferentHash = Types.Constructor(::ActiveSupport::HashWithIndifferentAccess) do |value|
|
16
|
+
Types::Coercible::Hash[value].with_indifferent_access
|
17
|
+
end
|
18
|
+
|
19
|
+
# A type to validate skip paths
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
SkipPaths = Types::Hash.map(
|
23
|
+
Types::Coercible::String,
|
24
|
+
Types::Array.of(Types::String | Types.Instance(Regexp))
|
25
|
+
)
|
26
|
+
|
27
|
+
# A type to make arrays of strings
|
28
|
+
StringList = Types::Array.of(Types::String).default { [] }
|
29
|
+
|
30
|
+
# A type to parse timestamps
|
31
|
+
# @api private
|
32
|
+
Timestamp = Types.Constructor(::Time) do |value|
|
33
|
+
# :nocov:
|
34
|
+
case value
|
35
|
+
when Integer then ::Time.at(value)
|
36
|
+
when ::Time then value
|
37
|
+
when Types.Interface(:to_time) then value.to_time
|
38
|
+
end
|
39
|
+
# :nocov:
|
40
|
+
end.optional
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KeycloakRack
|
4
|
+
# Adds `config` as a property without using {KeycloakRack::Import},
|
5
|
+
# for instances where dependency injection doesn't make sense.
|
6
|
+
#
|
7
|
+
# @!visibility private
|
8
|
+
module WithConfig
|
9
|
+
# @!attribute [r] config
|
10
|
+
# @return [KeycloakRack::Config]
|
11
|
+
def config
|
12
|
+
KeycloakRack::Container["keycloak-rack.config"]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
2.7.2
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
4
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
5
|
+
|
6
|
+
require_relative "config/application"
|
7
|
+
|
8
|
+
Rails.application.load_tasks
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ApplicationController < ActionController::API
|
4
|
+
before_action :authenticate_user!
|
5
|
+
|
6
|
+
# @return [void]
|
7
|
+
def authenticate_user!
|
8
|
+
request.env["keycloak:session"].authenticate! do |m|
|
9
|
+
m.success(:authenticated) do |_, token|
|
10
|
+
@current_user = { keycloak_id: token.keycloak_id }
|
11
|
+
end
|
12
|
+
|
13
|
+
m.success do
|
14
|
+
@current_user = { anonymous: true }
|
15
|
+
end
|
16
|
+
|
17
|
+
m.failure do |code, reason|
|
18
|
+
render json: { errors: [{ message: "Auth Failure" }] }, status: :forbidden
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "boot"
|
4
|
+
|
5
|
+
require "rails"
|
6
|
+
# Pick the frameworks you want:
|
7
|
+
require "active_model/railtie"
|
8
|
+
require "active_job/railtie"
|
9
|
+
# require "active_record/railtie"
|
10
|
+
# require "active_storage/engine"
|
11
|
+
require "action_controller/railtie"
|
12
|
+
# require "action_mailer/railtie"
|
13
|
+
# require "action_mailbox/engine"
|
14
|
+
# require "action_text/engine"
|
15
|
+
require "action_view/railtie"
|
16
|
+
# require "action_cable/engine"
|
17
|
+
# require "sprockets/railtie"
|
18
|
+
# require "rails/test_unit/railtie"
|
19
|
+
|
20
|
+
require "keycloak_rack"
|
21
|
+
|
22
|
+
# Require the gems listed in Gemfile, including any gems
|
23
|
+
# you've limited to :test, :development, or :production.
|
24
|
+
Bundler.require(*Rails.groups)
|
25
|
+
|
26
|
+
module Dummy
|
27
|
+
class Application < Rails::Application
|
28
|
+
# Initialize configuration defaults for originally generated Rails version.
|
29
|
+
|
30
|
+
case ENV["BUNDLE_GEMFILE"]
|
31
|
+
when /rails_6_0/
|
32
|
+
config.load_defaults 6.0
|
33
|
+
config.hosts << "www.example.com"
|
34
|
+
when /rails_6_1/
|
35
|
+
config.load_defaults 6.1
|
36
|
+
config.hosts << "www.example.com"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Configuration for the application, engines, and railties goes here.
|
40
|
+
#
|
41
|
+
# These settings can be overridden in specific environments using the files
|
42
|
+
# in config/environments, which are processed later.
|
43
|
+
#
|
44
|
+
# config.time_zone = "Central Time (US & Canada)"
|
45
|
+
# config.eager_load_paths << Rails.root.join("extras")
|
46
|
+
|
47
|
+
# Only loads a smaller set of middleware suitable for API only apps.
|
48
|
+
# Middleware like session, flash, cookies can be added back manually.
|
49
|
+
# Skip views, helpers and assets when generating a new resource.
|
50
|
+
config.api_only = true
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/integer/time"
|
4
|
+
|
5
|
+
# The test environment is used exclusively to run your application's
|
6
|
+
# test suite. You never need to work with it otherwise. Remember that
|
7
|
+
# your test database is "scratch space" for the test suite and is wiped
|
8
|
+
# and recreated between test runs. Don't rely on the data there!
|
9
|
+
|
10
|
+
Rails.application.configure do
|
11
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
12
|
+
|
13
|
+
config.cache_classes = true
|
14
|
+
|
15
|
+
# Do not eager load code on boot. This avoids loading your whole application
|
16
|
+
# just for the purpose of running a single test. If you are using a tool that
|
17
|
+
# preloads Rails for running tests, you may have to set it to true.
|
18
|
+
config.eager_load = false
|
19
|
+
|
20
|
+
# Configure public file server for tests with Cache-Control for performance.
|
21
|
+
config.public_file_server.enabled = true
|
22
|
+
config.public_file_server.headers = {
|
23
|
+
'Cache-Control' => "public, max-age=#{1.hour.to_i}"
|
24
|
+
}
|
25
|
+
|
26
|
+
# Show full error reports and disable caching.
|
27
|
+
config.consider_all_requests_local = true
|
28
|
+
config.action_controller.perform_caching = false
|
29
|
+
config.cache_store = :null_store
|
30
|
+
|
31
|
+
# Raise exceptions instead of rendering exception templates.
|
32
|
+
config.action_dispatch.show_exceptions = false
|
33
|
+
|
34
|
+
# Disable request forgery protection in test environment.
|
35
|
+
config.action_controller.allow_forgery_protection = false
|
36
|
+
|
37
|
+
# Print deprecation notices to the stderr.
|
38
|
+
config.active_support.deprecation = :stderr
|
39
|
+
|
40
|
+
# Raise exceptions for disallowed deprecations.
|
41
|
+
config.active_support.disallowed_deprecation = :raise
|
42
|
+
|
43
|
+
# Tell Active Support which deprecation messages to disallow.
|
44
|
+
config.active_support.disallowed_deprecation_warnings = []
|
45
|
+
|
46
|
+
# Raises error for missing translations.
|
47
|
+
# config.i18n.raise_on_missing_translations = true
|
48
|
+
|
49
|
+
# Annotate rendered view with file names.
|
50
|
+
# config.action_view.annotate_rendered_view_with_filenames = true
|
51
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/integer/time"
|
4
|
+
|
5
|
+
# The test environment is used exclusively to run your application's
|
6
|
+
# test suite. You never need to work with it otherwise. Remember that
|
7
|
+
# your test database is "scratch space" for the test suite and is wiped
|
8
|
+
# and recreated between test runs. Don't rely on the data there!
|
9
|
+
|
10
|
+
Rails.application.configure do
|
11
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
12
|
+
|
13
|
+
config.cache_classes = true
|
14
|
+
|
15
|
+
# Do not eager load code on boot. This avoids loading your whole application
|
16
|
+
# just for the purpose of running a single test. If you are using a tool that
|
17
|
+
# preloads Rails for running tests, you may have to set it to true.
|
18
|
+
config.eager_load = false
|
19
|
+
|
20
|
+
# Configure public file server for tests with Cache-Control for performance.
|
21
|
+
config.public_file_server.enabled = true
|
22
|
+
config.public_file_server.headers = {
|
23
|
+
'Cache-Control' => "public, max-age=#{1.hour.to_i}"
|
24
|
+
}
|
25
|
+
|
26
|
+
# Show full error reports and disable caching.
|
27
|
+
config.consider_all_requests_local = true
|
28
|
+
config.action_controller.perform_caching = false
|
29
|
+
config.cache_store = :null_store
|
30
|
+
|
31
|
+
# Raise exceptions instead of rendering exception templates.
|
32
|
+
config.action_dispatch.show_exceptions = false
|
33
|
+
|
34
|
+
# Disable request forgery protection in test environment.
|
35
|
+
config.action_controller.allow_forgery_protection = false
|
36
|
+
|
37
|
+
# Print deprecation notices to the stderr.
|
38
|
+
config.active_support.deprecation = :stderr
|
39
|
+
|
40
|
+
# Raise exceptions for disallowed deprecations.
|
41
|
+
config.active_support.disallowed_deprecation = :raise
|
42
|
+
|
43
|
+
# Tell Active Support which deprecation messages to disallow.
|
44
|
+
config.active_support.disallowed_deprecation_warnings = []
|
45
|
+
|
46
|
+
# Raises error for missing translations.
|
47
|
+
# config.i18n.raise_on_missing_translations = true
|
48
|
+
|
49
|
+
# Annotate rendered view with file names.
|
50
|
+
# config.action_view.annotate_rendered_view_with_filenames = true
|
51
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Be sure to restart your server when you modify this file.
|
4
|
+
|
5
|
+
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
|
6
|
+
# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
|
7
|
+
|
8
|
+
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code
|
9
|
+
# by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'".
|
10
|
+
Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Be sure to restart your server when you modify this file.
|
3
|
+
|
4
|
+
# Avoid CORS issues when API is called from the frontend app.
|
5
|
+
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
|
6
|
+
|
7
|
+
# Read more: https://github.com/cyu/rack-cors
|
8
|
+
|
9
|
+
# Rails.application.config.middleware.insert_before 0, Rack::Cors do
|
10
|
+
# allow do
|
11
|
+
# origins 'example.com'
|
12
|
+
#
|
13
|
+
# resource '*',
|
14
|
+
# headers: :any,
|
15
|
+
# methods: [:get, :post, :put, :patch, :delete, :options, :head]
|
16
|
+
# end
|
17
|
+
# end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Be sure to restart your server when you modify this file.
|
4
|
+
|
5
|
+
# Configure sensitive parameters which will be filtered from the log file.
|
6
|
+
Rails.application.config.filter_parameters += [
|
7
|
+
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
|
8
|
+
]
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Be sure to restart your server when you modify this file.
|
3
|
+
|
4
|
+
# Add new inflection rules using the following format. Inflections
|
5
|
+
# are locale specific, and you may define rules for as many different
|
6
|
+
# locales as you wish. All of these examples are active by default:
|
7
|
+
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
8
|
+
# inflect.plural /^(ox)$/i, '\1en'
|
9
|
+
# inflect.singular /^(ox)en/i, '\1'
|
10
|
+
# inflect.irregular 'person', 'people'
|
11
|
+
# inflect.uncountable %w( fish sheep )
|
12
|
+
# end
|
13
|
+
|
14
|
+
# These inflection rules are supported but not enabled by default:
|
15
|
+
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
16
|
+
# inflect.acronym 'RESTful'
|
17
|
+
# end
|