Class: Otto::Security::Authentication::RouteAuthWrapper

Inherits:
Object
  • Object
show all
Defined in:
lib/otto/security/authentication/route_auth_wrapper.rb

Overview

Wraps route handlers with authentication and authorization

This is the main orchestrator that: - Sets anonymous StrategyResult for unauthenticated routes - Enforces authentication for protected routes - Supports multi-strategy with OR logic (first authenticated success wins) - Performs Layer 1 (route-level) role authorization

Multi-strategy chain semantics (in precedence order): - AUTHENTICATED success wins immediately; later strategies never run. - TERMINAL failure (AuthFailure with terminal: true — explicit credentials examined and rejected) halts the chain and fails closed, regardless of strategy order. An anonymous success from an anonymous-capable strategy elsewhere in the chain does not rescue the request. See AuthFailure. - ANONYMOUS success (StrategyResult with no user, e.g. from noauth) is held as a fallback while the rest of the chain runs. It wins once the chain completes without an authenticated success or terminal failure, so credential-less requests still fall through to noauth. When more than one strategy produces an anonymous success, the first declared is the fallback; later ones are deliberately ignored. - Plain failures are recorded and the next strategy is consulted (OR logic). If everything fails, an AuthorizationFailure (valid credential, denied) yields 403; otherwise 401.

Examples:

Basic usage

wrapper = RouteAuthWrapper.new(handler, route_def, auth_config)
response = wrapper.call(env)

See Also:

  • for strategy lookup
  • for error responses
  • for role checking

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(wrapped_handler, route_definition, auth_config, security_config = nil) ⇒ RouteAuthWrapper

Returns a new instance of RouteAuthWrapper.



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/otto/security/authentication/route_auth_wrapper.rb', line 46

def initialize(wrapped_handler, route_definition, auth_config, security_config = nil)
  @wrapped_handler  = wrapped_handler
  @route_definition = route_definition
  @auth_config      = auth_config
  @security_config  = security_config

  # Initialize extracted components
  @strategy_resolver = RouteAuthWrapperComponents::StrategyResolver.new(auth_config)
  @response_builder  = RouteAuthWrapperComponents::ResponseBuilder.new(route_definition, auth_config, security_config)
  @role_authorizer   = RouteAuthWrapperComponents::RoleAuthorization.new(route_definition)
end

Instance Attribute Details

#auth_configObject (readonly)

Returns the value of attribute auth_config.



44
45
46
# File 'lib/otto/security/authentication/route_auth_wrapper.rb', line 44

def auth_config
  @auth_config
end

#route_definitionObject (readonly)

Returns the value of attribute route_definition.



44
45
46
# File 'lib/otto/security/authentication/route_auth_wrapper.rb', line 44

def route_definition
  @route_definition
end

#security_configObject (readonly)

Returns the value of attribute security_config.



44
45
46
# File 'lib/otto/security/authentication/route_auth_wrapper.rb', line 44

def security_config
  @security_config
end

#wrapped_handlerObject (readonly)

Returns the value of attribute wrapped_handler.



44
45
46
# File 'lib/otto/security/authentication/route_auth_wrapper.rb', line 44

def wrapped_handler
  @wrapped_handler
end

Instance Method Details

#call(env, extra_params = {}) ⇒ Array

Execute authentication then call wrapped handler

Parameters:

  • env (Hash)

    Rack environment

  • extra_params (Hash) (defaults to: {})

    Additional parameters

Returns:

  • (Array)

    Rack response array



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/otto/security/authentication/route_auth_wrapper.rb', line 63

def call(env, extra_params = {})
  auth_requirements = route_definition.auth_requirements

  # Routes without auth requirement get anonymous StrategyResult
  return handle_anonymous_route(env, extra_params) if auth_requirements.empty?

  # Validate all strategies exist before executing any (fail-fast)
  validation_error = validate_strategies(auth_requirements, env)
  return validation_error if validation_error

  # Try each strategy in order (first authenticated success wins;
  # anonymous success is a fallback; terminal failure halts the chain)
  authenticate_and_authorize(env, extra_params, auth_requirements)
end