Class: OmniauthOpenidFederation::KeyExtractor

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

Class Method Summary collapse

Class Method Details

.extract_encryption_key(jwks: nil, metadata: nil, private_key: nil) ⇒ OpenSSL::PKey::RSA?

Extract encryption key from JWKS or metadata

Parameters:

  • jwks (Hash, Array, nil) (defaults to: nil)

    JWKS hash or array of keys

  • metadata (Hash, nil) (defaults to: nil)

    Metadata hash containing JWKS

  • private_key (OpenSSL::PKey::RSA, String, nil) (defaults to: nil)

    Fallback private key if JWKS not available

Returns:

  • (OpenSSL::PKey::RSA, nil)

    Encryption key or nil if not found



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

def self.extract_encryption_key(jwks: nil, metadata: nil, private_key: nil)
  # Try to extract from JWKS first
  if jwks || 
    keys = extract_keys_from_jwks(jwks: jwks, metadata: )
    encryption_key_data = find_key_by_use(keys, "enc")

    if encryption_key_data
      return jwk_to_openssl_key(encryption_key_data)
    end

    # If no encryption key found but keys exist, try first key without use field (backward compatibility)
    if keys.any?
      first_key = keys.first
      unless first_key["use"] # Only use if no use field specified
        return jwk_to_openssl_key(first_key)
      end
    end
  end

  # Fallback to provided private_key (backward compatibility)
  if private_key
    return normalize_private_key(private_key)
  end

  nil
end

.extract_key(jwks: nil, metadata: nil, use: nil, private_key: nil) ⇒ OpenSSL::PKey::RSA?

Extract key by use value or fallback to single key

Parameters:

  • jwks (Hash, Array, nil) (defaults to: nil)

    JWKS hash or array of keys

  • metadata (Hash, nil) (defaults to: nil)

    Metadata hash containing JWKS

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

    Use value (“sig” or “enc”)

  • private_key (OpenSSL::PKey::RSA, String, nil) (defaults to: nil)

    Fallback private key

Returns:

  • (OpenSSL::PKey::RSA, nil)

    Key or nil if not found



90
91
92
93
94
95
96
97
98
99
100
# File 'lib/omniauth_openid_federation/key_extractor.rb', line 90

def self.extract_key(jwks: nil, metadata: nil, use: nil, private_key: nil)
  if use == "sig"
    extract_signing_key(jwks: jwks, metadata: , private_key: private_key)
  elsif use == "enc"
    extract_encryption_key(jwks: jwks, metadata: , private_key: private_key)
  else
    # No use specified, try signing first, then encryption, then fallback
    extract_signing_key(jwks: jwks, metadata: , private_key: private_key) ||
      extract_encryption_key(jwks: jwks, metadata: , private_key: private_key)
  end
end

.extract_signing_key(jwks: nil, metadata: nil, private_key: nil) ⇒ OpenSSL::PKey::RSA?

Extract signing key from JWKS or metadata

Parameters:

  • jwks (Hash, Array, nil) (defaults to: nil)

    JWKS hash or array of keys

  • metadata (Hash, nil) (defaults to: nil)

    Metadata hash containing JWKS

  • private_key (OpenSSL::PKey::RSA, String, nil) (defaults to: nil)

    Fallback private key if JWKS not available

Returns:

  • (OpenSSL::PKey::RSA, nil)

    Signing key or nil if not found



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/omniauth_openid_federation/key_extractor.rb', line 23

def self.extract_signing_key(jwks: nil, metadata: nil, private_key: nil)
  # Try to extract from JWKS first
  if jwks || 
    keys = extract_keys_from_jwks(jwks: jwks, metadata: )
    signing_key_data = find_key_by_use(keys, "sig")

    if signing_key_data
      return jwk_to_openssl_key(signing_key_data)
    end

    # If no signing key found but keys exist, try first key without use field (backward compatibility)
    if keys.any?
      first_key = keys.first
      unless first_key["use"] # Only use if no use field specified
        return jwk_to_openssl_key(first_key)
      end
    end
  end

  # Fallback to provided private_key (backward compatibility)
  if private_key
    return normalize_private_key(private_key)
  end

  nil
end

.jwk_to_openssl_key(jwk_data) ⇒ OpenSSL::PKey::RSA

Convert JWK hash to OpenSSL key (private or public)

Parameters:

  • jwk_data (Hash)

    JWK hash

Returns:

  • (OpenSSL::PKey::RSA)

    OpenSSL key



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/omniauth_openid_federation/key_extractor.rb', line 151

def self.jwk_to_openssl_key(jwk_data)
  # Use JWT::JWK if available (jwt gem 2.7+)
  # JWT::JWK.import handles both public and private keys and is OpenSSL 3.0 compatible
  if defined?(JWT::JWK)
    jwk = JWT::JWK.import(jwk_data)
    # JWT::JWK::RSA has keypair method for private keys, public_key for public keys
    if jwk_data[:d] || jwk_data["d"]
      # Private key - use keypair method
      jwk.keypair
    else
      # Public key
      jwk.public_key
    end
  else
    # Fallback: Manual conversion (OpenSSL 2.x compatible only)
    # For OpenSSL 3.0, JWT::JWK is required
    raise ArgumentError, "JWT::JWK is required for OpenSSL 3.0 compatibility. Please ensure jwt gem >= 2.7 is installed."
  end
end