Class: OmniauthOpenidFederation::Federation::TrustChainResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/omniauth_openid_federation/federation/trust_chain_resolver.rb

Overview

Trust Chain Resolver for OpenID Federation 1.0

Resolves and validates trust chains from a Leaf Entity to a Trust Anchor.

Instance Method Summary collapse

Constructor Details

#initialize(leaf_entity_id:, trust_anchors:, max_chain_length: 10, timeout: 10) ⇒ TrustChainResolver

Initialize resolver

Parameters:

  • leaf_entity_id (String)

    Entity Identifier of the Leaf Entity

  • trust_anchors (Array<Hash>)

    Array of Trust Anchor configurations Each hash must have:

    • :entity_id or “entity_id” - Trust Anchor Entity Identifier

    • :jwks or “jwks” - Trust Anchor JWKS for validation

  • max_chain_length (Integer) (defaults to: 10)

    Maximum chain length to prevent infinite loops (default: 10)

  • timeout (Integer) (defaults to: 10)

    HTTP request timeout in seconds (default: 10)



45
46
47
48
49
50
51
52
# File 'lib/omniauth_openid_federation/federation/trust_chain_resolver.rb', line 45

def initialize(leaf_entity_id:, trust_anchors:, max_chain_length: 10, timeout: 10)
  @leaf_entity_id = leaf_entity_id
  @trust_anchors = normalize_trust_anchors(trust_anchors)
  @max_chain_length = max_chain_length
  @timeout = timeout
  @resolved_statements = []
  @visited_entities = Set.new
end

Instance Method Details

#resolve!Array<Hash>

Resolve the trust chain

Returns:

  • (Array<Hash>)

    Array of validated entity statements in order (Leaf to Trust Anchor)

Raises:



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/omniauth_openid_federation/federation/trust_chain_resolver.rb', line 59

def resolve!
  OmniauthOpenidFederation::Logger.debug("[TrustChainResolver] Starting trust chain resolution for: #{@leaf_entity_id}")

  leaf_config = fetch_entity_configuration(@leaf_entity_id)
  validate_entity_statement(leaf_config, nil)
  @resolved_statements << leaf_config
  @visited_entities.add(@leaf_entity_id)

  current_entity_id = @leaf_entity_id
  current_config = leaf_config

  while current_config && !is_trust_anchor?(current_config)
    authority_hints = extract_authority_hints(current_config)

    if StringHelpers.blank?(authority_hints)
      raise ValidationError, "Entity #{current_entity_id} has no authority_hints and is not a Trust Anchor"
    end

    found_next = false
    authority_hints.each do |authority_id|
      next if @visited_entities.include?(authority_id)

      if @resolved_statements.length >= @max_chain_length
        raise ValidationError, "Trust chain length exceeds maximum (#{@max_chain_length})"
      end

      begin
        subordinate_statement = fetch_subordinate_statement(
          issuer: authority_id,
          subject: current_entity_id
        )

        issuer_config = fetch_entity_configuration(authority_id)
        validate_entity_statement(subordinate_statement, issuer_config)

        @resolved_statements << subordinate_statement
        @visited_entities.add(authority_id)

        current_entity_id = authority_id
        current_config = issuer_config
        found_next = true
        break
      rescue ValidationError, FetchError => e
        OmniauthOpenidFederation::Logger.warn("[TrustChainResolver] Failed to resolve via #{authority_id}: #{e.message}")
        OmniauthOpenidFederation::Instrumentation.notify_trust_chain_validation_failed(
          entity_id: current_entity_id,
          trust_anchor: authority_id,
          validation_step: "subordinate_statement_validation",
          error_message: e.message,
          error_class: e.class.name
        )
        next
      end
    end

    unless found_next
      raise ValidationError, "Could not resolve trust chain from #{current_entity_id}: no valid authority found"
    end
  end

  unless is_trust_anchor?(current_config)
    error_msg = "Trust chain did not terminate at a configured Trust Anchor"
    OmniauthOpenidFederation::Instrumentation.notify_trust_chain_validation_failed(
      entity_id: @leaf_entity_id,
      trust_anchor: current_entity_id,
      validation_step: "trust_anchor_verification",
      error_message: error_msg
    )
    raise ValidationError, error_msg
  end

  OmniauthOpenidFederation::Logger.debug("[TrustChainResolver] Trust chain resolved: #{@resolved_statements.length} statements")
  @resolved_statements
end