Class: OmniauthOpenidFederation::EntityStatementReader

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

Constant Summary collapse

JWT_PARTS_COUNT =

Standard JWT has 3 parts: header.payload.signature

3

Class Method Summary collapse

Class Method Details

.fetch_keys(entity_statement_path: nil) ⇒ Array<Hash>

Fetch JWKS keys from entity statement

Parameters:

  • entity_statement_path (String, nil) (defaults to: nil)

    Path to entity statement file

Returns:

  • (Array<Hash>)

    Array of JWK hash objects



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/omniauth_openid_federation/entity_statement_reader.rb', line 32

def fetch_keys(entity_statement_path: nil)
  entity_statement = load_entity_statement(entity_statement_path)
  return [] if StringHelpers.blank?(entity_statement)

  # Decode self-signed entity statement
  # Entity statements are self-signed, so we validate using their own JWKS
  # First, decode without validation to get the JWKS
  jwt_parts = entity_statement.split(".")
  return [] if jwt_parts.length != JWT_PARTS_COUNT

  # Decode payload (second part)
  payload = JSON.parse(Base64.urlsafe_decode64(jwt_parts[1]))

  # Extract JWKS from entity statement claims
  payload.fetch("jwks", {}).fetch("keys", [])

  # Return JWK hashes directly (no need to convert to objects)
end

.parse_metadata(entity_statement_path: nil) ⇒ Hash?

Parse provider metadata from entity statement

Parameters:

  • entity_statement_path (String, nil) (defaults to: nil)

    Path to entity statement file

Returns:

  • (Hash, nil)

    Hash with provider metadata or nil if not found



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/omniauth_openid_federation/entity_statement_reader.rb', line 55

def (entity_statement_path: nil)
  entity_statement = load_entity_statement(entity_statement_path)
  return nil if StringHelpers.blank?(entity_statement)

  # Decode JWT payload
  jwt_parts = entity_statement.split(".")
  return nil if jwt_parts.length != JWT_PARTS_COUNT

  claims = JSON.parse(Base64.urlsafe_decode64(jwt_parts[1]))

  # Extract provider metadata
   = claims.fetch("metadata", {})
   = .fetch("openid_provider", {})

  {
    issuer: ["issuer"],
    authorization_endpoint: ["authorization_endpoint"],
    token_endpoint: ["token_endpoint"],
    userinfo_endpoint: ["userinfo_endpoint"],
    jwks_uri: ["jwks_uri"],
    signed_jwks_uri: ["signed_jwks_uri"],
    entity_issuer: claims["iss"],
    entity_jwks: claims.fetch("jwks", {})
  }
end

.validate_fingerprint(entity_statement_content, expected_fingerprint) ⇒ Boolean

Validate entity statement fingerprint

Parameters:

  • entity_statement_content (String)

    The entity statement content

  • expected_fingerprint (String)

    The expected SHA-256 fingerprint

Returns:

  • (Boolean)

    true if fingerprints match



86
87
88
89
90
# File 'lib/omniauth_openid_federation/entity_statement_reader.rb', line 86

def validate_fingerprint(entity_statement_content, expected_fingerprint)
  calculated = Digest::SHA256.hexdigest(entity_statement_content).downcase
  expected = expected_fingerprint.downcase
  calculated == expected
end