class KeycloakRack::Middleware
Rack middleware that calls {KeycloakRack::Authenticate} to process a keycloak token.
Upon successful processing, it populates the following values into the rack environment for consumption later down the stack:
-
`keycloak:session`: An instance of {KeycloakRack::Session} that serves as the primary interface
-
`keycloak:authorize_realm`: An instance of {KeycloakRack::AuthorizeRealm} for authorizing realm-level roles
-
`keycloak:authorize_resource`: An instance of {KeycloakRack::AuthorizeResource} for authorizing resource-level roles
Public Class Methods
@param [#call] app the next component in the rack middleware stack
# File lib/keycloak_rack/middleware.rb, line 18 def initialize(app, **options) super(**options) @app = app end
Public Instance Methods
Process the rack environment and inject the gem's interfaces into it.
If the authentication is a monadic failure, and {KeycloakRack::Config#halt_on_auth_failure halt_on_auth_failure} is true, then it will short-circuit with {#authentication_failed}.
@param [Hash] env the rack environment @return [Object]
# File lib/keycloak_rack/middleware.rb, line 31 def call(env) result = authenticate.call(env) return authentication_failed(env, result) if halt?(result) session_opts = { skipped: false, auth_result: result } case result in Success[:authenticated, decoded_token] session_opts[:token] = decoded_token in Success[:skipped] session_opts[:skipped] = true else # nothing to do end env["keycloak:session"] = session = KeycloakRack::Session.new(**session_opts) env["keycloak:authorize_realm"] = session.authorize_realm env["keycloak:authorize_resource"] = session.authorize_resource @app.call(env) end
Private Instance Methods
Build the authentication failure when short-circuiting.
@note See {#build_failure_headers} and {#build_failure_body} for opportunities
to override.
@param [Hash] env the rack environment @param [Dry::Monads::Result] monad @return [(Integer, { String => String }, <String>)] rack response
# File lib/keycloak_rack/middleware.rb, line 63 def authentication_failed(env, monad) status = build_failure_status env, monad headers = build_failure_headers env, monad body = build_failure_body env, monad # :nocov: body = body.to_json unless body.kind_of?(String) # :nocov: [ status, headers, [ body ] ] end
@todo Make customizable @note Currently uses GraphQL error format. @param [Hash] env the rack environment @param [Dry::Monads::Result] monad @return [String, to_json]
# File lib/keycloak_rack/middleware.rb, line 110 def build_failure_body(env, monad) _reason, message, _token, _original_error = monad.failure { errors: [ { message: message, extensions: { code: "UNAUTHENTICATED" } } ] } end
@todo Make customizable @param [Hash] env the rack environment @param [Dry::Monads::Result] monad @return [{ String => String }]
# File lib/keycloak_rack/middleware.rb, line 99 def build_failure_headers(env, monad) { "Content-Type" => "application/json" } end
# File lib/keycloak_rack/middleware.rb, line 81 def build_failure_status(env, monad) case monad in Failure[:no_token, _] 401 in Failure[:expired, String, String, Exception] 403 in Failure[Symbol, String, String, Exception] 400 else 500 # nothing to do end end
@param [Dry::Monads::Result] result
# File lib/keycloak_rack/middleware.rb, line 126 def halt?(result) return false unless result.failure? config.halt_on_auth_failure? end