Class: LcpRuby::Authentication::OmniAuthBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/lcp_ruby/authentication/omniauth_builder.rb

Overview

Translates Provider value objects into OmniAuth strategy registrations. Called from the lcp_ruby.omniauth engine initializer at boot.

Constant Summary collapse

DISCOVERY_SUFFIX =
%r{/\.well-known/openid-configuration/?\z}.freeze

Class Method Summary collapse

Class Method Details

.derive_issuer(discovery_url) ⇒ Object

Strips the discovery suffix so the strategy receives a bare issuer URL. Examples:

https://login.microsoftonline.com/<tenant>/v2.0/.well-known/openid-configuration
  → https://login.microsoftonline.com/<tenant>/v2.0
https://accounts.google.com/.well-known/openid-configuration
  → https://accounts.google.com

Falls through unchanged when the suffix isn’t present (e.g. some IdPs publish a non-standard discovery path that the operator pasted as-is). Raises ConfigurationError on blank input — ‘omniauth_openid_connect` would silently accept `issuer: “”` and fail with an opaque error at the first request; AuthValidator already guarantees a non-blank discovery_url at boot, so reaching this with a blank value is a bug.



96
97
98
99
100
101
102
# File 'lib/lcp_ruby/authentication/omniauth_builder.rb', line 96

def derive_issuer(discovery_url)
  if discovery_url.to_s.strip.empty?
    raise LcpRuby::Authentication::ConfigurationError,
          "OmniAuthBuilder.derive_issuer requires a non-blank discovery_url"
  end
  discovery_url.to_s.sub(DISCOVERY_SUFFIX, "")
end

.install_middleware!(app) ⇒ Object

Engine entry point. Registers ‘OmniAuth::Builder` middleware on the given Rails application iff at least one OIDC provider is configured, and sets `OmniAuth.config.path_prefix` so the middleware listens at the engine-relative `<mount>/auth` URL (NOT the default `/auth`).

Returns true when middleware was added, false when the call was a no-op (the gate this method enforces is the contract relied on by built_in-only / :external / :none deployments — the middleware must not appear when nothing OIDC is configured).

Both the path_prefix and the redirect_uri are derived from ‘LcpRuby.configuration.mount_path` so they stay in sync. Hosts that mount the engine at a non-root path MUST set `config.mount_path` accordingly (validated by AuthValidator at boot for OIDC installs).



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/lcp_ruby/authentication/omniauth_builder.rb', line 33

def install_middleware!(app)
  return false unless ProviderRegistry.oidc_enabled?

  OmniAuth.config.failure_raise_out_environments = []
  OmniAuth.config.path_prefix = "#{normalized_mount_path}/auth"

  oidc_providers = ProviderRegistry.all.select(&:oidc?)
  app.middleware.use OmniAuth::Builder do
    oidc_providers.each { |provider| OmniAuthBuilder.register(self, provider) }
  end
  true
rescue LcpRuby::Authentication::ConfigurationError => e
  # In production, fail loud — a misconfigured auth.yml in prod must
  # not silently disable OIDC. In dev/test/CI, log a warning and skip
  # middleware so `rake lcp_ruby:validate` (which depends on
  # `:environment`) can run and surface the issue in its report.
  raise if defined?(Rails) && Rails.respond_to?(:env) && Rails.env.production?

  log_skipped_install(e)
  false
end

.normalized_mount_pathObject

Normalises ‘LcpRuby.configuration.mount_path` to the form expected by URL prefixes: empty string for root mounts, leading slash and no trailing slash otherwise. Single source of truth for both `path_prefix` and `build_redirect_uri`.



59
60
61
62
63
# File 'lib/lcp_ruby/authentication/omniauth_builder.rb', line 59

def normalized_mount_path
  mount = LcpRuby.configuration.mount_path.to_s
  mount = "/#{mount}" unless mount.start_with?("/")
  mount == "/" ? "" : mount.chomp("/")
end

.register(builder, provider) ⇒ Object

Registers an :openid_connect strategy on the given OmniAuth::Builder using config drawn from the provider entry. Discovery is enabled and ‘issuer` is derived from `discovery_url` (strip the well-known suffix); `omniauth_openid_connect` then calls `Config.discover!(issuer)`, which appends `/.well-known/openid-configuration` and pulls authorization / token / userinfo / jwks / end_session endpoints from the IdP.



71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/lcp_ruby/authentication/omniauth_builder.rb', line 71

def register(builder, provider)
  builder.provider :openid_connect,
                   name: provider.name.to_sym,
                   issuer: derive_issuer(provider.discovery_url),
                   discovery: true,
                   scope: provider.scopes.map(&:to_sym),
                   response_type: provider.response_type.to_sym,
                   response_mode: provider.response_mode.to_sym,
                   send_nonce: true,
                   pkce: provider.pkce,
                   client_options: client_options(provider)
end