Class: Himari::ItemProviders::OauthClientMetadata

Inherits:
Object
  • Object
show all
Includes:
Himari::ItemProvider
Defined in:
lib/himari/item_providers/oauth_client_metadata.rb

Overview

Resolves clients whose client_id is an https URL pointing to a JSON client metadata document, per draft-ietf-oauth-client-id-metadata-document. When the OIDC endpoints look a client up by id, this provider fetches and validates that document on demand and presents it as a public ClientRegistration.

The HTTPX session is built once and retained for connection reuse; successful documents are cached in-memory (respecting HTTP cache headers within configured bounds). Errors and malformed documents are never cached, and the provider always fails closed (returns []), so a fetch problem surfaces as an unknown client rather than an exception.

Defined Under Namespace

Classes: CacheEntry, FetchError, InvalidDocument

Instance Method Summary collapse

Constructor Details

#initialize(session:, allowed_client_ids: [], require_pkce: true, ignore_localhost_redirect_uri_port: true, skip_consent: false, scopes: Himari::ClientRegistration::IMPLICIT_SCOPES, max_response_size: 5120, cache_min_ttl: 60, cache_max_ttl: 86400, cache_default_ttl: 300, cache_max_total_size: 1_048_576, logger: nil) ⇒ OauthClientMetadata

Returns a new instance of OauthClientMetadata.

Parameters:

  • session (HTTPX::Session)

    persistent, SSRF-filtered session (built by the middleware)

  • allowed_client_ids (Array<String, Regexp>) (defaults to: [])

    empty = allow any compliant https URL



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/himari/item_providers/oauth_client_metadata.rb', line 36

def initialize(session:, allowed_client_ids: [], require_pkce: true, ignore_localhost_redirect_uri_port: true,
  skip_consent: false, scopes: Himari::ClientRegistration::IMPLICIT_SCOPES,
  max_response_size: 5120,
  cache_min_ttl: 60, cache_max_ttl: 86400, cache_default_ttl: 300, cache_max_total_size: 1_048_576, logger: nil)
  @session = session
  @allowed_client_ids = allowed_client_ids
  @require_pkce = require_pkce
  @ignore_localhost_redirect_uri_port = ignore_localhost_redirect_uri_port
  @skip_consent = skip_consent
  @scopes = scopes
  @max_response_size = max_response_size
  @cache_min_ttl = cache_min_ttl
  @cache_max_ttl = cache_max_ttl
  @cache_default_ttl = cache_default_ttl
  @cache_max_total_size = cache_max_total_size
  @logger = logger
  @cache = Concurrent::Map.new
  @cache_total_size = Concurrent::AtomicFixnum.new(0)
  @cache_seq = Concurrent::AtomicFixnum.new(0)
end

Instance Method Details

#collect(id: nil, **_hint) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/himari/item_providers/oauth_client_metadata.rb', line 57

def collect(id: nil, **_hint)
  return [] unless id.is_a?(String)
  return [] unless compliant_client_id_url?(id)
  return [] unless allowed?(id)

  cached = cache_get(id)
  return [cached] if cached

  registration, ttl, size = fetch_and_build(id)
  cache_put(id, registration, ttl, size) if ttl.positive?
  [registration]
rescue HTTPX::Error, FetchError, InvalidDocument, JSON::ParserError, Himari::DynamicClientRegistration::ValidationError => e
  @logger&.warn(Himari::LogLine.new('OauthClientMetadata: client_id rejected', client_id: id, error: e.message))
  []
end