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
49
50
51
52
53
54
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
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
# File 'lib/omniauth_openid_federation/access_token.rb', line 23
def resource_request
res = yield
status_code = if res.status.is_a?(Integer)
res.status
else
(res.status.respond_to?(:code) ? res.status.code : res.status)
end
case status_code
when 200
if /\A[\w\-.]+\z/.match?(res.body)
is_encrypted = res.body.split(".").length == 5
if is_encrypted
encryption_key =
plain_text = JWE.decrypt(res.body, encryption_key)
if plain_text.split(".").length == 3
signed_jwt = plain_text
else
begin
return JSON.parse(plain_text).with_indifferent_access
rescue JSON::ParserError
signed_jwt = plain_text
end
end
else
signed_jwt = res.body
end
strategy_options = get_strategy_options
raw_client_options = strategy_options[:client_options] || strategy_options["client_options"] || {}
client_options = OmniauthOpenidFederation::Validators.normalize_hash(raw_client_options)
jwks_uri_value = client_options[:jwks_uri] || ((respond_to?(:client) && client&.respond_to?(:jwks_uri)) ? client.jwks_uri : nil)
jwks_uri =
if jwks_uri_value && %r{https?://.+}.match?(jwks_uri_value.to_s)
URI.parse(jwks_uri_value.to_s)
elsif jwks_uri_value
URI::HTTPS.build(
host: client_options[:host] || ((respond_to?(:client) && client&.respond_to?(:host)) ? client.host : nil),
path: jwks_uri_value.to_s
)
else
nil
end
normalized_strategy_options = OmniauthOpenidFederation::Validators.normalize_hash(strategy_options)
begin
= signed_jwt.split(".").first
= JSON.parse(Base64.urlsafe_decode64())
algorithm = ["alg"] || [:alg]
if algorithm == "none" || algorithm.nil?
jwt = ::JWT.decode(signed_jwt, nil, false)
else
signed_jwks = fetch_signed_jwks(normalized_strategy_options)
if signed_jwks
jwt = ::JWT.decode(
signed_jwt,
nil,
true,
{algorithms: [algorithm], jwks: signed_jwks}
)
else
unless jwks_uri
OmniauthOpenidFederation::Logger.debug("[AccessToken] JWKS URI not in client_options, trying to resolve from entity statement")
jwks_uri = resolve_jwks_uri_from_entity_statement(normalized_strategy_options)
if jwks_uri
OmniauthOpenidFederation::Logger.debug("[AccessToken] Successfully resolved JWKS URI from entity statement")
jwks_uri = URI.parse(jwks_uri) if jwks_uri.is_a?(String) && !jwks_uri.is_a?(URI)
end
end
unless jwks_uri
error_msg = "JWKS URI not available. Cannot verify JWT signature. Provide jwks_uri in client_options or entity statement."
OmniauthOpenidFederation::Logger.error("[AccessToken] #{error_msg}")
raise OmniauthOpenidFederation::ConfigurationError, error_msg
end
entity_statement_keys = load_entity_statement_keys_for_jwks_validation(normalized_strategy_options)
jwt = OmniauthOpenidFederation::Jwks::Decode.jwt(
signed_jwt,
jwks_uri.to_s,
entity_statement_keys: entity_statement_keys
)
end
end
rescue => e
OmniauthOpenidFederation::Logger.warn("[AccessToken] Failed to parse JWT header, trying unsigned decode: #{e.message}")
jwt = ::JWT.decode(signed_jwt, nil, false)
end
jwt.first.with_indifferent_access
else
JSON.parse(res.body).with_indifferent_access
end
when 400
raise BadRequest.new("API Access Faild", res)
when 401
raise Unauthorized.new("Access Token Invalid or Expired", res)
when 403
raise Forbidden.new("Insufficient Scope", res)
else
raise HttpError.new(res.status, "Unknown HttpError", res)
end
end
|