-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for known providers to OIDC #22176
Conversation
This adds specifc config to enable OIDC login for the main OIDC providers. Having explicit config options like this makes it easy to search the documentation/dev UI for it. Fixes quarkusio#20783
ret.credentials.secret = Optional.of(config.provider.microsoft.get().secret); | ||
ret.authServerUrl = Optional.of("https://login.microsoftonline.com/common/v2.0"); | ||
//TODO: do we want to hard code this? | ||
ret.applicationType = OidcTenantConfig.ApplicationType.HYBRID; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, not sure, I'd have to test it on my app to see if it works.
ret.authentication.scopes = Optional.of(config.provider.github.get().scopes); | ||
ret.authentication.userInfoRequired = true; | ||
ret.authentication.setIdTokenRequired(false); | ||
ret.authentication.setRedirectPath("/Login/githubLoginSuccess"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think those links are too specific to my app. But in practice:
- google/apple/ms works on a single endpoint without requiring
UserInfo
: everything is in the ID Token - github must be handled specially because
UserInfo
contains the user ID, name and user name, but we have to hit a second endpoint/user/emails
to get the user's email. - facebook must be handled specially because
UserInfo
contains the user ID, name and email
Perhaps a better endpoint default would be: /{provider}-oidc-login-success
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naturally, a further layer of abstraction which knows how to fetch the damn fields from all providers and present them to the Quarkus user would be even better: then I only need a single success endpoint :)
But that can wait for another issue.
Hi @stuartwdouglas Thanks for taking on this task. I'd like to clarify first, how will the configuration look like ? For example, a user should be able to override any property in the
I think for this to work |
* Config for well known OIDC providers | ||
*/ | ||
@ConfigItem | ||
public ProvidersConfig provider; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it has to be decoupled from OidcTenantConfig
, it has to be part of OidcTenantConfig
, tenant specific as needed, or rather, IMHO, something like quarkus.oidc.provider=github
should point to an instance of OidcTenantConfig
, merged with the OidcTenantConfig
referencing it, please see below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, just realized, this way won't work with the dynamic TenantConfigResolver
- one should be able to do, instead of defining this config statically in application.properties
,
public class MyTenantConfigResolver implements TenantConfigResolver {
public Uni<OidcTenantConfig> resolve(RoutingContext rc)
{
OidcTenantConfig github = getDefaultOidcTenantGithubBlock();
// overrride:
github.getAuthentication().setScope("user:something");
return github;
}
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stuartwdouglas Stuart, how about having an OidcTenantConfig
provider
enum property with (github
, etc, values).
This will allow OidcRecorder
, when going over every OidcTenantConfig
, pick up a referenced well-known provider OidcTenantConfig
instance and merge with the current OidcTenantConfig
- it will address all the concerns I've expressed in various comments here
for (var e : knownProviders.entrySet()) { | ||
var provider = e.getValue().get(); | ||
if (provider.isPresent()) { | ||
tenants.put(e.getKey(), provider.get()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, but it is not correct - it creates a dedicated tenant per every social provider config, but it won't allow to override a specific property using OidcTenantConfig
- with this approach we'd end up moving a good portion of OidcTenantConfig
properties under the github
and other provider specific blocks. I'd say it is a problem.
I understand that GitHub
and other config groups you have added are meant to customize - but it creates a parallel stream for configuring things.
But also equally important, it does not allow to vary with the provider, each OIDC tenant allows to have:
quarkus.oidc.github1.provider=github
quarkus.oidc.github1.authentication.scopes=a
quarkus.oidc.github2.provider=github
quarkus.oidc.github2.authentication.scopes=b
It may not be something one would want to do in production but for tests it is very useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, so continuing from the earlier comment, so you have Map<String, Supplier<Optional<OidcTenantConfig>>> knownProviders
.
But instead of creating tenants as you have typed here, the following will be more aligned with the OIDC tenancy:
if (oidcTenantConfig.provider.isPresent()) {
// Merge - this ensures the github/etc properties are overridable
OidcTenantConfig thisIsCurrentTenantConfig = new OidcTenantConfig(knownProviders.get(oidcTenantConfig.provider.get()));
// continue dealing with this tenant config
}
import io.quarkus.runtime.annotations.ConfigItem; | ||
|
||
@ConfigGroup | ||
public class GitHub { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, GitHub
(and other providers) groups should extend OidcTenantConfig
and override properties with GitHub/etc specific properties
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
client-id
, client-secret
, scopes
- these are all available in OidcTenantConfig
, this is my earlier concern, it is not worth IMHO to start mirroring some of those properties here. By extending OidcTenantConfig
they can be set as needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I now think that these groups have to be removed, IMHO, the supplied OidcTenantConfig
per every provider should be enough
ret.credentials.secret = Optional.of(config.provider.github.get().secret); | ||
ret.authServerUrl = Optional.of("https://github.com/login/oauth"); | ||
//TODO: do we want to hard code this? | ||
ret.applicationType = OidcTenantConfig.ApplicationType.HYBRID; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HYBRID
won't work for GitHub - quarkus-oidc
service
apps can not handle opaque tokens from providers like GitHub since it has no introspection endpoint - I've opened an issue to make sure a userinfo check is enough
ret.authentication.scopes = Optional.of(config.provider.github.get().scopes); | ||
ret.authentication.userInfoRequired = true; | ||
ret.authentication.setIdTokenRequired(false); | ||
ret.authentication.setRedirectPath("/Login/githubLoginSuccess"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it has to be an application specific property
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also agree with @sberyozkin that we could rely on the properties already available from OidcTenantConfig
. But looks like there are some improvements on documentation and dev UI.
I would also add a hook for each provider so that the authorization/authentication response could be processed accordingly to the particularities of providers. For instance, github might require calling additional endpoints to fetch info about the subject, etc. Perhaps it could also avoid simplifying the code a bit by not introducing provider-specific behavior into the main code path. Another example is Apple ID, which requires setting up a JWT to authenticate.
Hi @pedroigor
@FroMage is on it, the existing JWT gen code will be reused - but will be sent as a client post secret value. Providing plugin points for provider specific behaviors is a nice idea, I propose though to deal with it separately as this PR is complex in its own way :-) |
Hi Stuart, I did a quick prototype based on my comments, https://github.com/sberyozkin/quarkus/pull/new/well_known_providers. It will allow the following variations:
Note especially in the last case - the client authentication requirements may differ (with Apple it would be a fairly complex JWT auth setup) which is what I implied that we'd need to mirror It works in Hope it looks reasonable, I'll try to complete it soon enough, the only real complexity is copying |
This one has been superseded by #22572. |
This adds specifc config to enable OIDC login for the main OIDC
providers. Having explicit config options like this makes it easy to
search the documentation/dev UI for it.
Fixes #20783