verikloak-audience 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +10 -0
- data/lib/verikloak/audience/checker.rb +35 -2
- data/lib/verikloak/audience/configuration.rb +113 -3
- data/lib/verikloak/audience/errors.rb +20 -2
- data/lib/verikloak/audience/middleware.rb +31 -5
- data/lib/verikloak/audience/railtie.rb +6 -0
- data/lib/verikloak/audience/version.rb +1 -1
- metadata +6 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 0fb9e7977881b01b0bd15bad81ebf1a49e279ae3f5e2cefb9d978c6579c9fceb
         | 
| 4 | 
            +
              data.tar.gz: 778b0260bb771b2e5d14f18b2cda54ce19567a5ee727f85ade281e8331170e44
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 26a8bfcc5c5d714b1376dd88b4e7a27c530806f6d935f8d2b3665b3c7c52d7345782ad1df40a3d7fb63b912e899aa33f27e79ddb6b39c05074b256dfd0c99fe0
         | 
| 7 | 
            +
              data.tar.gz: 359a268c4ad3567c83dc93f1a6a348f8a8b8c22cb0067fced9c1473cd9285a7b7bb64b4a10b09d397b4de305a28221678238da1bdc7c0adb4ccf2632a18d0232
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |
| 7 7 |  | 
| 8 8 | 
             
            ---
         | 
| 9 9 |  | 
| 10 | 
            +
            ## [0.2.0] - 2025-09-21
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ### Added
         | 
| 13 | 
            +
            - README "Operational safeguards" section covering startup validation, logger precedence, and `:resource_or_aud` alignment guidance.
         | 
| 14 | 
            +
            - YARD documentation for configuration helpers and middleware logging routines.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            ### Changed
         | 
| 17 | 
            +
            - Tightened `resource_client` inference/validation to enforce alignment with `required_aud` and infer single-entry clients automatically.
         | 
| 18 | 
            +
            - Prefer request-scoped loggers over `Kernel#warn` when emitting audience failure messages.
         | 
| 19 | 
            +
            - Bumped runtime dependency to `verikloak >= 0.1.5` to pick up shared logger support.
         | 
| 20 | 
            +
            - Improved Rails Railtie test harness to mimic real initializer registration.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ## [0.1.1] - 2025-09-20
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            ### Changed
         | 
| 25 | 
            +
            - Documented `Configuration#safe_dup` behaviour and tightened duplication semantics.
         | 
| 26 | 
            +
            - Expanded error class YARD docs to clarify operational response codes.
         | 
| 27 | 
            +
             | 
| 10 28 | 
             
            ## [0.1.0] - 2025-09-20
         | 
| 11 29 |  | 
| 12 30 | 
             
            ### Added
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,5 +1,10 @@ | |
| 1 1 | 
             
            # verikloak-audience
         | 
| 2 2 |  | 
| 3 | 
            +
            [](https://github.com/taiyaky/verikloak-audience/actions/workflows/ci.yml)
         | 
| 4 | 
            +
            [](https://rubygems.org/gems/verikloak-audience)
         | 
| 5 | 
            +
            
         | 
| 6 | 
            +
            [](https://rubygems.org/gems/verikloak-audience)
         | 
| 7 | 
            +
             | 
| 3 8 | 
             
            Rack middleware for validating the `aud` claim of Keycloak-issued tokens on top of the Verikloak stack. It ships with deploy-friendly presets that address common Keycloak patterns such as `account` co-existence and `resource_access`-driven role enforcement.
         | 
| 4 9 |  | 
| 5 10 | 
             
            For the full error behaviour (response shapes, exception classes, logging hints), see [ERRORS.md](ERRORS.md).
         | 
| @@ -53,6 +58,11 @@ See [`examples/rack.ru`](examples/rack.ru) for a full Rack sample. In Rails, alw | |
| 53 58 |  | 
| 54 59 | 
             
            `env_claims_key` assumes the preceding `Verikloak::Middleware` populates the Rack env. If the middleware order changes, claims will be missing and the audience check will always reject.
         | 
| 55 60 |  | 
| 61 | 
            +
            ### Operational safeguards
         | 
| 62 | 
            +
            - Middleware initialisation now fails fast when `required_aud` is empty. When Rails loads via the supplied Railtie, `Verikloak::Audience.config.validate!` runs after boot so configuration mistakes surface during startup instead of returning 403 for every request.
         | 
| 63 | 
            +
            - When audience validation fails, the middleware consults `env['verikloak.logger']`, `env['rack.logger']`, and `env['action_dispatch.logger']` (in that order) before falling back to Ruby's `Kernel#warn`, keeping failure logs consistent with Rails and Verikloak observers.
         | 
| 64 | 
            +
            - For the `:resource_or_aud` profile, `resource_client` must match one of the values in `required_aud`. A single-element `required_aud` automatically infers the client id, ensuring the same client identifier is shared with downstream BFF/Pundit integrations.
         | 
| 65 | 
            +
             | 
| 56 66 | 
             
            ## Testing
         | 
| 57 67 | 
             
            All pull requests and pushes are automatically tested with [RSpec](https://rspec.info/) and [RuboCop](https://rubocop.org/) via GitHub Actions.
         | 
| 58 68 | 
             
            See the CI badge at the top for current build status.
         | 
| @@ -7,6 +7,8 @@ module Verikloak | |
| 7 7 | 
             
                # This module provides predicate helpers used by the middleware to decide
         | 
| 8 8 | 
             
                # whether a given set of claims satisfies the configured profile.
         | 
| 9 9 | 
             
                module Checker
         | 
| 10 | 
            +
                  VALID_PROFILES = %i[strict_single allow_account resource_or_aud].freeze
         | 
| 11 | 
            +
             | 
| 10 12 | 
             
                  module_function
         | 
| 11 13 |  | 
| 12 14 | 
             
                  # Returns whether the given claims satisfy the configured profile.
         | 
| @@ -15,8 +17,16 @@ module Verikloak | |
| 15 17 | 
             
                  # @param cfg [Verikloak::Audience::Configuration]
         | 
| 16 18 | 
             
                  # @return [Boolean]
         | 
| 17 19 | 
             
                  def ok?(claims, cfg)
         | 
| 18 | 
            -
                     | 
| 19 | 
            -
             | 
| 20 | 
            +
                    claims = normalize_claims(claims)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    profile = cfg.profile
         | 
| 23 | 
            +
                    profile = profile.to_sym if profile.respond_to?(:to_sym)
         | 
| 24 | 
            +
                    profile = :strict_single if profile.nil?
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    unless VALID_PROFILES.include?(profile)
         | 
| 27 | 
            +
                      raise Verikloak::Audience::ConfigurationError,
         | 
| 28 | 
            +
                            "unknown audience profile #{cfg.profile.inspect}"
         | 
| 29 | 
            +
                    end
         | 
| 20 30 |  | 
| 21 31 | 
             
                    case profile
         | 
| 22 32 | 
             
                    when :strict_single
         | 
| @@ -77,6 +87,8 @@ module Verikloak | |
| 77 87 | 
             
                  # @param cfg [Verikloak::Audience::Configuration]
         | 
| 78 88 | 
             
                  # @return [:strict_single, :allow_account, :resource_or_aud]
         | 
| 79 89 | 
             
                  def suggest(claims, cfg)
         | 
| 90 | 
            +
                    claims = normalize_claims(claims)
         | 
| 91 | 
            +
             | 
| 80 92 | 
             
                    aud = Array(claims['aud']).map(&:to_s)
         | 
| 81 93 | 
             
                    req = cfg.required_aud_list
         | 
| 82 94 | 
             
                    has_roles = !Array(claims.dig('resource_access', cfg.resource_client.to_s, 'roles')).empty?
         | 
| @@ -87,6 +99,27 @@ module Verikloak | |
| 87 99 |  | 
| 88 100 | 
             
                    :strict_single
         | 
| 89 101 | 
             
                  end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  # Normalize incoming claims to a Hash to guard against unexpected
         | 
| 104 | 
            +
                  # env payloads or middleware ordering issues.
         | 
| 105 | 
            +
                  #
         | 
| 106 | 
            +
                  # @param claims [Object]
         | 
| 107 | 
            +
                  # @return [Hash]
         | 
| 108 | 
            +
                  def normalize_claims(claims)
         | 
| 109 | 
            +
                    return {} if claims.nil?
         | 
| 110 | 
            +
                    return claims if claims.is_a?(Hash)
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    if claims.respond_to?(:to_hash)
         | 
| 113 | 
            +
                      coerced = claims.to_hash
         | 
| 114 | 
            +
                      return coerced if coerced.is_a?(Hash)
         | 
| 115 | 
            +
                    end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                    {}
         | 
| 118 | 
            +
                  rescue StandardError
         | 
| 119 | 
            +
                    {}
         | 
| 120 | 
            +
                  end
         | 
| 121 | 
            +
                  module_function :normalize_claims
         | 
| 122 | 
            +
                  private_class_method :normalize_claims
         | 
| 90 123 | 
             
                end
         | 
| 91 124 | 
             
              end
         | 
| 92 125 | 
             
            end
         | 
| @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'verikloak/audience/errors'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            module Verikloak
         | 
| 4 6 | 
             
              module Audience
         | 
| 5 7 | 
             
                # Configuration holder for verikloak-audience.
         | 
| @@ -20,8 +22,11 @@ module Verikloak | |
| 20 22 | 
             
                #   Whether to log a suggestion when audience validation fails.
         | 
| 21 23 | 
             
                #   @return [Boolean]
         | 
| 22 24 | 
             
                class Configuration
         | 
| 25 | 
            +
                  DEFAULT_RESOURCE_CLIENT = 'rails-api'
         | 
| 26 | 
            +
             | 
| 23 27 | 
             
                  attr_accessor :profile, :required_aud, :resource_client,
         | 
| 24 | 
            -
                                : | 
| 28 | 
            +
                                :suggest_in_logs
         | 
| 29 | 
            +
                  attr_reader :env_claims_key
         | 
| 25 30 |  | 
| 26 31 | 
             
                  # Create a configuration with safe defaults.
         | 
| 27 32 | 
             
                  #
         | 
| @@ -29,17 +34,122 @@ module Verikloak | |
| 29 34 | 
             
                  def initialize
         | 
| 30 35 | 
             
                    @profile         = :strict_single
         | 
| 31 36 | 
             
                    @required_aud    = []
         | 
| 32 | 
            -
                    @resource_client =  | 
| 33 | 
            -
                     | 
| 37 | 
            +
                    @resource_client = DEFAULT_RESOURCE_CLIENT
         | 
| 38 | 
            +
                    self.env_claims_key = 'verikloak.user'
         | 
| 34 39 | 
             
                    @suggest_in_logs = true
         | 
| 35 40 | 
             
                  end
         | 
| 36 41 |  | 
| 42 | 
            +
                  # Ensure `dup` produces an independent copy.
         | 
| 43 | 
            +
                  #
         | 
| 44 | 
            +
                  # @param source [Configuration]
         | 
| 45 | 
            +
                  # @return [void]
         | 
| 46 | 
            +
                  def initialize_copy(source)
         | 
| 47 | 
            +
                    super
         | 
| 48 | 
            +
                    @profile         = safe_dup(source.profile)
         | 
| 49 | 
            +
                    @required_aud    = duplicate_required_aud(source.required_aud)
         | 
| 50 | 
            +
                    @resource_client = safe_dup(source.resource_client)
         | 
| 51 | 
            +
                    self.env_claims_key = safe_dup(source.env_claims_key)
         | 
| 52 | 
            +
                    @suggest_in_logs = source.suggest_in_logs
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 37 55 | 
             
                  # Coerce `required_aud` into an array of strings.
         | 
| 38 56 | 
             
                  #
         | 
| 39 57 | 
             
                  # @return [Array<String>]
         | 
| 40 58 | 
             
                  def required_aud_list
         | 
| 41 59 | 
             
                    Array(required_aud).map(&:to_s)
         | 
| 42 60 | 
             
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  # @param value [#to_s, nil]
         | 
| 63 | 
            +
                  # @return [void]
         | 
| 64 | 
            +
                  def env_claims_key=(value)
         | 
| 65 | 
            +
                    @env_claims_key = value&.to_s
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  # Validate the configuration to ensure required values are present.
         | 
| 69 | 
            +
                  #
         | 
| 70 | 
            +
                  # @return [Configuration] the validated configuration
         | 
| 71 | 
            +
                  def validate!
         | 
| 72 | 
            +
                    audiences = required_aud_list
         | 
| 73 | 
            +
                    if audiences.empty?
         | 
| 74 | 
            +
                      raise Verikloak::Audience::ConfigurationError,
         | 
| 75 | 
            +
                            'required_aud must include at least one audience'
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                    profile_name = profile
         | 
| 79 | 
            +
                    profile_name = profile_name.to_sym if profile_name.respond_to?(:to_sym)
         | 
| 80 | 
            +
                    profile_name ||= :strict_single
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                    ensure_resource_client!(audiences) if profile_name == :resource_or_aud
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    self
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  private
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  # Attempt to duplicate a value while tolerating non-duplicable inputs.
         | 
| 90 | 
            +
                  # Returns `nil` when given nil and falls back to the original on duplication errors.
         | 
| 91 | 
            +
                  #
         | 
| 92 | 
            +
                  # @param value [Object, nil]
         | 
| 93 | 
            +
                  # @return [Object, nil]
         | 
| 94 | 
            +
                  def safe_dup(value)
         | 
| 95 | 
            +
                    return if value.nil?
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    value.dup
         | 
| 98 | 
            +
                  rescue TypeError
         | 
| 99 | 
            +
                    value
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  # Build a deep-ish copy of `required_aud` so that mutations on copies
         | 
| 103 | 
            +
                  # do not leak back into the original configuration instance.
         | 
| 104 | 
            +
                  #
         | 
| 105 | 
            +
                  # @param value [Array<String,Symbol>, String, Symbol, nil]
         | 
| 106 | 
            +
                  # @return [Array<String,Symbol>, String, Symbol, nil]
         | 
| 107 | 
            +
                  def duplicate_required_aud(value)
         | 
| 108 | 
            +
                    return if value.nil?
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                    return value.map { |item| safe_dup(item) } if value.is_a?(Array)
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    safe_dup(value)
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  # Ensure that the configured `resource_client` fits the `required_aud`
         | 
| 116 | 
            +
                  # list when the :resource_or_aud profile is active. Attempts to infer
         | 
| 117 | 
            +
                  # the client id from `required_aud` when possible and raises when
         | 
| 118 | 
            +
                  # ambiguity remains.
         | 
| 119 | 
            +
                  #
         | 
| 120 | 
            +
                  # @param audiences [Array<String>] coerced required audiences
         | 
| 121 | 
            +
                  # @return [void]
         | 
| 122 | 
            +
                  def ensure_resource_client!(audiences)
         | 
| 123 | 
            +
                    client = resource_client.to_s
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                    needs_inference = needs_resource_client_inference?(client, audiences)
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                    if needs_inference
         | 
| 128 | 
            +
                      if audiences.one?
         | 
| 129 | 
            +
                        self.resource_client = audiences.first
         | 
| 130 | 
            +
                        client = resource_client.to_s
         | 
| 131 | 
            +
                      else
         | 
| 132 | 
            +
                        raise Verikloak::Audience::ConfigurationError,
         | 
| 133 | 
            +
                              'resource_client must match one of required_aud when using :resource_or_aud profile'
         | 
| 134 | 
            +
                      end
         | 
| 135 | 
            +
                    end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                    return if audiences.include?(client)
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                    raise Verikloak::Audience::ConfigurationError,
         | 
| 140 | 
            +
                          'resource_client must match one of required_aud when using :resource_or_aud profile'
         | 
| 141 | 
            +
                  end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                  # Decide whether the resource client should be inferred from the
         | 
| 144 | 
            +
                  # required audiences based on the current client value.
         | 
| 145 | 
            +
                  #
         | 
| 146 | 
            +
                  # @param client [String]
         | 
| 147 | 
            +
                  # @param audiences [Array<String>]
         | 
| 148 | 
            +
                  # @return [Boolean]
         | 
| 149 | 
            +
                  def needs_resource_client_inference?(client, audiences)
         | 
| 150 | 
            +
                    client.empty? ||
         | 
| 151 | 
            +
                      (client == DEFAULT_RESOURCE_CLIENT && !audiences.include?(client))
         | 
| 152 | 
            +
                  end
         | 
| 43 153 | 
             
                end
         | 
| 44 154 | 
             
              end
         | 
| 45 155 | 
             
            end
         | 
| @@ -23,12 +23,30 @@ module Verikloak | |
| 23 23 | 
             
                  end
         | 
| 24 24 | 
             
                end
         | 
| 25 25 |  | 
| 26 | 
            -
                # Raised when  | 
| 26 | 
            +
                # Raised when verified claims do not satisfy the configured profile.
         | 
| 27 | 
            +
                # Typically emitted when the required audience list is empty or
         | 
| 28 | 
            +
                # mismatches the token audiences.
         | 
| 27 29 | 
             
                class Forbidden < Error
         | 
| 28 | 
            -
                  #  | 
| 30 | 
            +
                  # Build a forbidden error with a customizable message while preserving
         | 
| 31 | 
            +
                  # the standard machine-friendly code and HTTP status.
         | 
| 32 | 
            +
                  #
         | 
| 33 | 
            +
                  # @param msg [String] alternate human-readable explanation
         | 
| 29 34 | 
             
                  def initialize(msg = 'insufficient audience')
         | 
| 30 35 | 
             
                    super(msg, code: 'insufficient_audience', http_status: 403)
         | 
| 31 36 | 
             
                  end
         | 
| 32 37 | 
             
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # Raised when configuration is invalid.
         | 
| 40 | 
            +
                # Used when runtime configuration checks detect missing or incompatible
         | 
| 41 | 
            +
                # values before audience validation takes place.
         | 
| 42 | 
            +
                class ConfigurationError < Error
         | 
| 43 | 
            +
                  # Build a configuration error while keeping a consistent error code
         | 
| 44 | 
            +
                  # and a 500 HTTP status to signal an internal misconfiguration.
         | 
| 45 | 
            +
                  #
         | 
| 46 | 
            +
                  # @param msg [String] alternate human-readable explanation
         | 
| 47 | 
            +
                  def initialize(msg = 'invalid audience configuration')
         | 
| 48 | 
            +
                    super(msg, code: 'audience_configuration_error', http_status: 500)
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 33 51 | 
             
              end
         | 
| 34 52 | 
             
            end
         | 
| @@ -22,8 +22,9 @@ module Verikloak | |
| 22 22 | 
             
                  # @option opts [Boolean] :suggest_in_logs
         | 
| 23 23 | 
             
                  def initialize(app, **opts)
         | 
| 24 24 | 
             
                    @app = app
         | 
| 25 | 
            -
                    @config = Verikloak::Audience. | 
| 25 | 
            +
                    @config = Verikloak::Audience.config.dup
         | 
| 26 26 | 
             
                    apply_overrides!(opts)
         | 
| 27 | 
            +
                    @config.validate!
         | 
| 27 28 | 
             
                  end
         | 
| 28 29 |  | 
| 29 30 | 
             
                  # Evaluate the request against the audience profile.
         | 
| @@ -31,13 +32,15 @@ module Verikloak | |
| 31 32 | 
             
                  # @param env [Hash] Rack environment
         | 
| 32 33 | 
             
                  # @return [Array(Integer, Hash, #each)] Rack response triple
         | 
| 33 34 | 
             
                  def call(env)
         | 
| 34 | 
            -
                     | 
| 35 | 
            +
                    env_key = @config.env_claims_key
         | 
| 36 | 
            +
                    claims = env[env_key] || env[env_key&.to_sym] || {}
         | 
| 35 37 | 
             
                    return @app.call(env) if Checker.ok?(claims, @config)
         | 
| 36 38 |  | 
| 37 39 | 
             
                    if @config.suggest_in_logs
         | 
| 38 40 | 
             
                      suggestion = Checker.suggest(claims, @config)
         | 
| 39 41 | 
             
                      aud_view = Array(claims['aud']).inspect
         | 
| 40 | 
            -
                       | 
| 42 | 
            +
                      log_warning(env,
         | 
| 43 | 
            +
                                  "[verikloak-audience] insufficient_audience; suggestion profile=:#{suggestion} aud=#{aud_view}")
         | 
| 41 44 | 
             
                    end
         | 
| 42 45 |  | 
| 43 46 | 
             
                    body = { error: 'insufficient_audience',
         | 
| @@ -50,12 +53,35 @@ module Verikloak | |
| 50 53 |  | 
| 51 54 | 
             
                  # Apply provided options to the configuration instance.
         | 
| 52 55 | 
             
                  #
         | 
| 53 | 
            -
                  # @param opts [Hash]
         | 
| 56 | 
            +
                  # @param opts [Hash] raw overrides provided to the middleware
         | 
| 54 57 | 
             
                  # @return [void]
         | 
| 55 58 | 
             
                  def apply_overrides!(opts)
         | 
| 56 59 | 
             
                    cfg = @config
         | 
| 60 | 
            +
                    opts.each_key do |key|
         | 
| 61 | 
            +
                      writer = "#{key}="
         | 
| 62 | 
            +
                      next if cfg.respond_to?(writer)
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                      raise Verikloak::Audience::ConfigurationError,
         | 
| 65 | 
            +
                            "unknown middleware option :#{key}"
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
             | 
| 57 68 | 
             
                    opts.each do |k, v|
         | 
| 58 | 
            -
                      cfg.public_send("#{k}=", v) | 
| 69 | 
            +
                      cfg.public_send("#{k}=", v)
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  # Emit a warning for failed audience checks using request-scoped loggers
         | 
| 74 | 
            +
                  # when available.
         | 
| 75 | 
            +
                  #
         | 
| 76 | 
            +
                  # @param env [Hash] Rack environment
         | 
| 77 | 
            +
                  # @param message [String] warning payload
         | 
| 78 | 
            +
                  # @return [void]
         | 
| 79 | 
            +
                  def log_warning(env, message)
         | 
| 80 | 
            +
                    logger = env['verikloak.logger'] || env['rack.logger'] || env['action_dispatch.logger']
         | 
| 81 | 
            +
                    if logger.respond_to?(:warn)
         | 
| 82 | 
            +
                      logger.warn(message)
         | 
| 83 | 
            +
                    else
         | 
| 84 | 
            +
                      warn(message)
         | 
| 59 85 | 
             
                    end
         | 
| 60 86 | 
             
                  end
         | 
| 61 87 | 
             
                end
         | 
| @@ -33,6 +33,12 @@ module Verikloak | |
| 33 33 | 
             
                    self.class.insert_middleware(app)
         | 
| 34 34 | 
             
                  end
         | 
| 35 35 |  | 
| 36 | 
            +
                  initializer 'verikloak_audience.configuration' do
         | 
| 37 | 
            +
                    config.after_initialize do
         | 
| 38 | 
            +
                      Verikloak::Audience.config.validate!
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 36 42 | 
             
                  # Performs the insertion into the middleware stack when the core
         | 
| 37 43 | 
             
                  # Verikloak middleware is available. Extracted for testability without
         | 
| 38 44 | 
             
                  # requiring a full Rails boot process.
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: verikloak-audience
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - taiyaky
         | 
| @@ -35,20 +35,20 @@ dependencies: | |
| 35 35 | 
             
                requirements:
         | 
| 36 36 | 
             
                - - ">="
         | 
| 37 37 | 
             
                  - !ruby/object:Gem::Version
         | 
| 38 | 
            -
                    version: 0.1. | 
| 38 | 
            +
                    version: 0.1.5
         | 
| 39 39 | 
             
                - - "<"
         | 
| 40 40 | 
             
                  - !ruby/object:Gem::Version
         | 
| 41 | 
            -
                    version:  | 
| 41 | 
            +
                    version: 1.0.0
         | 
| 42 42 | 
             
              type: :runtime
         | 
| 43 43 | 
             
              prerelease: false
         | 
| 44 44 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 45 45 | 
             
                requirements:
         | 
| 46 46 | 
             
                - - ">="
         | 
| 47 47 | 
             
                  - !ruby/object:Gem::Version
         | 
| 48 | 
            -
                    version: 0.1. | 
| 48 | 
            +
                    version: 0.1.5
         | 
| 49 49 | 
             
                - - "<"
         | 
| 50 50 | 
             
                  - !ruby/object:Gem::Version
         | 
| 51 | 
            -
                    version:  | 
| 51 | 
            +
                    version: 1.0.0
         | 
| 52 52 | 
             
            description: |
         | 
| 53 53 | 
             
              Rack middleware that enforces audience checks with deployable profiles,
         | 
| 54 54 | 
             
              layering on top of Verikloak token verification.
         | 
| @@ -74,7 +74,7 @@ metadata: | |
| 74 74 | 
             
              source_code_uri: https://github.com/taiyaky/verikloak-audience
         | 
| 75 75 | 
             
              changelog_uri: https://github.com/taiyaky/verikloak-audience/blob/main/CHANGELOG.md
         | 
| 76 76 | 
             
              bug_tracker_uri: https://github.com/taiyaky/verikloak-audience/issues
         | 
| 77 | 
            -
              documentation_uri: https://rubydoc.info/gems/verikloak-audience/0. | 
| 77 | 
            +
              documentation_uri: https://rubydoc.info/gems/verikloak-audience/0.2.0
         | 
| 78 78 | 
             
              rubygems_mfa_required: 'true'
         | 
| 79 79 | 
             
            rdoc_options: []
         | 
| 80 80 | 
             
            require_paths:
         |