Skip to content

Commit 2939668

Browse files
committed
add basic openid auth
1 parent 4214772 commit 2939668

File tree

2 files changed

+103
-2
lines changed

2 files changed

+103
-2
lines changed

src/Access/AccessTokenProcessor.cpp

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,28 @@ std::unique_ptr<IAccessTokenProcessor> IAccessTokenProcessor::parseTokenProcesso
119119

120120
return std::make_unique<AzureAccessTokenProcessor>(name, cache_lifetime, email_regex_str, tenant_id_str);
121121
}
122+
else if (provider == "openid")
123+
{
124+
bool is_auto = config.hasProperty(prefix + ".configuration_endpoint");
125+
bool is_manual = config.hasProperty(prefix + ".userinfo_endpoint") &&
126+
config.hasProperty(prefix + ".token_introspection_endpoint") &&
127+
(config.hasProperty(prefix + ".userinfo_endpoint") == config.hasProperty(prefix + ".token_introspection_endpoint"));
128+
129+
if (is_auto && !is_manual)
130+
{
131+
return std::make_unique<OpenIDAccessTokenProcessor>(name, cache_lifetime, email_regex_str, config.getString(prefix + ".configuration_endpoint"));
132+
}
133+
else if (!is_auto && is_manual)
134+
{
135+
return std::make_unique<OpenIDAccessTokenProcessor>(name, cache_lifetime, email_regex_str, config.getString(prefix + ".userinfo_endpoint"), config.getString(prefix + ".token_introspection_endpoint"));
136+
}
137+
138+
throw Exception(ErrorCodes::INVALID_CONFIG_PARAMETER, "Could not parse access token processor {}: "
139+
"Either configuration_endpoint or both userinfo_endpoint and token_introspection_endpoint shall be specified", name);
140+
}
122141
else
123142
throw Exception(ErrorCodes::INVALID_CONFIG_PARAMETER,
124-
"Could not parse access token processor {}: unknown provider {}", name, provider);
143+
"Could not parse access token processor {}: unknown provider type {}", name, provider);
125144
}
126145

127146
throw Exception(ErrorCodes::INVALID_CONFIG_PARAMETER,
@@ -316,4 +335,57 @@ String AzureAccessTokenProcessor::validateTokenAndGetUsername(const String & tok
316335
return getValueByKey(user_info_json, "sub");
317336
}
318337

338+
OpenIDAccessTokenProcessor::OpenIDAccessTokenProcessor(const String & name_,
339+
const UInt64 cache_invalidation_interval_,
340+
const String & email_regex_str,
341+
const String & openid_config_endpoint_)
342+
: IAccessTokenProcessor(name_, cache_invalidation_interval_, email_regex_str)
343+
{
344+
const picojson::object openid_config = getObjectFromURI(Poco::URI(openid_config_endpoint_));
345+
346+
if (!openid_config.contains("userinfo_endpoint") || !openid_config.contains("introspection_endpoint"))
347+
throw Exception(ErrorCodes::AUTHENTICATION_FAILED, "{}: Cannot extract userinfo_endpoint or introspection_endpoint from OIDC configuration, consider manual configuration.", name);
348+
}
349+
350+
bool OpenIDAccessTokenProcessor::resolveAndValidate(const TokenCredentials & credentials)
351+
{
352+
const String & token = credentials.getToken();
353+
354+
try
355+
{
356+
String username = validateTokenAndGetUsername(token);
357+
if (!username.empty())
358+
{
359+
/// Credentials are passed as const everywhere up the flow, so we have to comply,
360+
/// in this case const_cast looks acceptable.
361+
const_cast<TokenCredentials &>(credentials).setUserName(username);
362+
}
363+
else
364+
LOG_TRACE(getLogger("AccessTokenProcessor"), "{}: Failed to get username with token", name);
365+
366+
}
367+
catch (...)
368+
{
369+
return false;
370+
}
371+
372+
return true;
373+
374+
/// TODO: add proper groups functionality
375+
// try
376+
// {
377+
// const_cast<TokenCredentials &>(credentials).setExpiresAt(jwt::decode(token).get_expires_at());
378+
// }
379+
// catch (...) {
380+
// LOG_TRACE(getLogger("AccessTokenProcessor"),
381+
// "{}: No expiration data found in a valid token, will use default cache lifetime", name);
382+
// }
383+
}
384+
385+
String OpenIDAccessTokenProcessor::validateTokenAndGetUsername(const String & token) const
386+
{
387+
picojson::object user_info_json = getObjectFromURI(userinfo_endpoint, token);
388+
return getValueByKey(user_info_json, "sub");
389+
}
390+
319391
}

src/Access/AccessTokenProcessor.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace ErrorCodes
2121
extern const int INVALID_CONFIG_PARAMETER;
2222
}
2323

24-
class GoogleAccessTokenProcessor;
24+
//class GoogleAccessTokenProcessor;
2525

2626
class IAccessTokenProcessor
2727
{
@@ -57,6 +57,8 @@ class IAccessTokenProcessor
5757
const String name;
5858
const UInt64 cache_invalidation_interval;
5959
re2::RE2 email_regex;
60+
61+
bool valid;
6062
};
6163

6264

@@ -97,4 +99,31 @@ class AzureAccessTokenProcessor : public IAccessTokenProcessor
9799
String validateTokenAndGetUsername(const String & token) const;
98100
};
99101

102+
class OpenIDAccessTokenProcessor : public IAccessTokenProcessor
103+
{
104+
public:
105+
/// Obtain endpoints from openid-configuration URL
106+
OpenIDAccessTokenProcessor(const String & name_,
107+
const UInt64 cache_invalidation_interval_,
108+
const String & email_regex_str,
109+
const String & openid_config_endpoint_);
110+
111+
/// Specify endpoints manually
112+
OpenIDAccessTokenProcessor(const String & name_,
113+
const UInt64 cache_invalidation_interval_,
114+
const String & email_regex_str,
115+
const String & userinfo_endpoint_,
116+
const String & token_introspection_endpoint_)
117+
: IAccessTokenProcessor(name_, cache_invalidation_interval_, email_regex_str),
118+
userinfo_endpoint(userinfo_endpoint_), token_introspection_endpoint(token_introspection_endpoint_) {}
119+
120+
bool resolveAndValidate(const TokenCredentials & credentials) override;
121+
private:
122+
const Poco::URI userinfo_endpoint;
123+
const Poco::URI token_introspection_endpoint;
124+
125+
126+
String validateTokenAndGetUsername(const String & token) const;
127+
};
128+
100129
}

0 commit comments

Comments
 (0)