Skip to content

Commit bbbc1a7

Browse files
committed
fix reading values from jsons
1 parent 134ffb7 commit bbbc1a7

File tree

1 file changed

+32
-22
lines changed

1 file changed

+32
-22
lines changed

src/Access/TokenProcessorsOpaque.cpp

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,23 @@ namespace
3030
return jsonValue.get<picojson::object>();
3131
}
3232

33-
template<typename ValueType = std::string>
34-
ValueType getValueByKey(const picojson::object & jsonObject, const std::string & key) {
33+
template<typename ValueType = std::string, bool throw_on_exception = true>
34+
std::optional<ValueType> getValueByKey(const picojson::object & jsonObject, const std::string & key) {
3535
auto it = jsonObject.find(key); // Find the key in the object
3636
if (it == jsonObject.end())
3737
{
38-
throw std::runtime_error("Key not found: " + key);
38+
if constexpr (throw_on_exception)
39+
throw std::runtime_error("Key not found: " + key);
40+
else
41+
return std::nullopt;
3942
}
4043

4144
const picojson::value & value = it->second;
4245
if (!value.is<ValueType>()) {
43-
throw std::runtime_error("Value for key '" + key + "' has incorrect type.");
46+
if constexpr (throw_on_exception)
47+
throw std::runtime_error("Value for key '" + key + "' has incorrect type.");
48+
else
49+
return std::nullopt;
4450
}
4551

4652
return value.get<ValueType>();
@@ -94,11 +100,9 @@ bool GoogleTokenProcessor::resolveAndValidate(const TokenCredentials & credentia
94100
throw Exception(ErrorCodes::AUTHENTICATION_FAILED,
95101
"{}: Specified username_claim {} not found in token", processor_name, username_claim);
96102

97-
bool has_email = user_info_json.contains("email");
98-
if (has_email)
99-
user_info["email"] = getValueByKey(user_info_json, "email");
103+
user_info["email"] = getValueByKey<std::string, false>(user_info_json, "email").value_or("");
100104

101-
user_info[username_claim] = getValueByKey(user_info_json, username_claim);
105+
user_info[username_claim] = getValueByKey(user_info_json, username_claim).value();
102106

103107
String user_name = user_info[username_claim];
104108

@@ -109,11 +113,11 @@ bool GoogleTokenProcessor::resolveAndValidate(const TokenCredentials & credentia
109113

110114
auto token_info = getObjectFromURI(Poco::URI("https://www.googleapis.com/oauth2/v3/tokeninfo"), token);
111115
if (token_info.contains("exp"))
112-
const_cast<TokenCredentials &>(credentials).setExpiresAt(std::chrono::system_clock::from_time_t((getValueByKey<time_t>(token_info, "exp"))));
116+
const_cast<TokenCredentials &>(credentials).setExpiresAt(std::chrono::system_clock::from_time_t((getValueByKey<time_t>(token_info, "exp").value())));
113117

114118
/// Groups info can only be retrieved if user email is known.
115119
/// If no email found in user info, we skip this step and there are no external roles for the user.
116-
if (has_email)
120+
if (!user_info["email"].empty())
117121
{
118122
std::set<String> external_groups_names;
119123
const Poco::URI get_groups_uri = Poco::URI("https://cloudidentity.googleapis.com/v1/groups/-/memberships:searchDirectGroups?query=member_key_id==" + user_info["email"] + "'");
@@ -139,10 +143,13 @@ bool GoogleTokenProcessor::resolveAndValidate(const TokenCredentials & credentia
139143
}
140144

141145
auto group_data = group.get<picojson::object>();
142-
String group_name = getValueByKey(group_data["groupKey"].get<picojson::object>(), "id");
143-
external_groups_names.insert(group_name);
144-
LOG_TRACE(getLogger("TokenAuthentication"),
145-
"{}: User {}: new external group {}", processor_name, user_name, group_name);
146+
String group_name = getValueByKey<std::string, false>(group_data["groupKey"].get<picojson::object>(), "id").value_or("");
147+
if (!group_name.empty())
148+
{
149+
external_groups_names.insert(group_name);
150+
LOG_TRACE(getLogger("TokenAuthentication"),
151+
"{}: User {}: new external group {}", processor_name, user_name, group_name);
152+
}
146153
}
147154

148155
const_cast<TokenCredentials &>(credentials).setGroups(external_groups_names);
@@ -172,7 +179,7 @@ bool AzureTokenProcessor::resolveAndValidate(const TokenCredentials & credential
172179
try
173180
{
174181
picojson::object user_info_json = getObjectFromURI(Poco::URI("https://graph.microsoft.com/oidc/userinfo"), token);
175-
String username = getValueByKey(user_info_json, username_claim);
182+
String username = getValueByKey(user_info_json, username_claim).value();
176183
if (!username.empty())
177184
{
178185
/// Credentials are passed as const everywhere up the flow, so we have to comply,
@@ -227,9 +234,12 @@ bool AzureTokenProcessor::resolveAndValidate(const TokenCredentials & credential
227234
if (!group_data.contains("displayName"))
228235
continue;
229236

230-
String group_name = getValueByKey(group_data, "displayName");
231-
external_groups_names.insert(group_name);
232-
LOG_TRACE(getLogger("TokenAuthentication"), "{}: User {}: new external group {}", processor_name, credentials.getUserName(), group_name);
237+
String group_name = getValueByKey<std::string, false>(group_data, "displayName").value_or("");
238+
if (!group_name.empty())
239+
{
240+
external_groups_names.insert(group_name);
241+
LOG_TRACE(getLogger("TokenAuthentication"), "{}: User {}: new external group {}", processor_name, credentials.getUserName(), group_name);
242+
}
233243
}
234244
}
235245
catch (const Exception & e)
@@ -285,7 +295,7 @@ OpenIdTokenProcessor::OpenIdTokenProcessor(const String & processor_name_,
285295
if (!openid_config.contains("userinfo_endpoint") || !openid_config.contains("introspection_endpoint"))
286296
throw Exception(ErrorCodes::AUTHENTICATION_FAILED, "{}: Cannot extract userinfo_endpoint or introspection_endpoint from OIDC configuration, consider manual configuration.", processor_name);
287297

288-
if (!openid_config.contains("jwks_uri"))
298+
if (openid_config.contains("jwks_uri"))
289299
{
290300
LOG_TRACE(getLogger("TokenAuthentication"), "{}: JWKS URI set, local JWT processing will be attempted", processor_name_);
291301
jwt_validator.emplace(processor_name_ + "jwks_val",
@@ -294,7 +304,7 @@ OpenIdTokenProcessor::OpenIdTokenProcessor(const String & processor_name_,
294304
groups_claim_,
295305
"",
296306
verifier_leeway_,
297-
getValueByKey(openid_config, "jwks_uri"),
307+
getValueByKey(openid_config, "jwks_uri").value(),
298308
jwks_cache_lifetime_);
299309
}
300310
}
@@ -311,7 +321,7 @@ bool OpenIdTokenProcessor::resolveAndValidate(const TokenCredentials & credentia
311321
{
312322
auto decoded_token = jwt::decode(token);
313323
user_info_json = decoded_token.get_payload_json();
314-
username = getValueByKey(user_info_json, username_claim);
324+
username = getValueByKey(user_info_json, username_claim).value();
315325

316326
/// TODO: Now we work only with Keycloak -- and it provides expires_at in token itself. Need to add actual token introspection logic for other OIDC providers.
317327
if (decoded_token.has_expires_at())
@@ -329,7 +339,7 @@ bool OpenIdTokenProcessor::resolveAndValidate(const TokenCredentials & credentia
329339
try
330340
{
331341
user_info_json = getObjectFromURI(userinfo_endpoint, token);
332-
username = getValueByKey(user_info_json, username_claim);
342+
username = getValueByKey(user_info_json, username_claim).value();
333343
}
334344
catch (...)
335345
{

0 commit comments

Comments
 (0)