Skip to content
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

Keycloak allowing all issuers not working as expected #29861

Closed
Mert18 opened this issue Dec 14, 2022 · 3 comments
Closed

Keycloak allowing all issuers not working as expected #29861

Mert18 opened this issue Dec 14, 2022 · 3 comments

Comments

@Mert18
Copy link
Contributor

Mert18 commented Dec 14, 2022

Describe the bug

I have a keycloak server and multiple realms. I am allowed to introduce only one of them to my quarkus application via setting quarkus.oidc.auth-server-url. I also set client.id and client.secret as they are required for Quarkus application to work. But I have jwts issued from different keycloak realms, and I want my application to skip the verification skip and allow all the jwts that are issued from different realms. The amount of my realms changes frequently so giving them as list is not an option for me. I want to skip the verification step and allow all the jwts.
Setting quarkus.oidc.token.issuer to "any" did not solve my problem, it still gave the following error:

Token verification has failed: Unable to process JOSE object (cause: org.jose4j.lang.UnresolvableKeyException: JWK with kid 'xxxx' is not available): JsonWebSignature{......

But when I set the quarkus.oidc.auth-server-url to where the jwt is issued, it works.

I tried things from the following issues:
#16294

Expected behavior

I expected quarkus not to check the validity of the jwt with the realm, and allow tokens from all issuers.

Actual behavior

Quarkus gives 401 Unauthorized error with the following debug message:

Token verification has failed: Unable to process JOSE object (cause: org.jose4j.lang.UnresolvableKeyException: JWK with kid 'xxxx' is not available): JsonWebSignature{......

How to Reproduce?

Create a quarkus realm and configure keycloak.

  1. Create two realms in keycloak. Create private gatekeeper clients for both of them.
  2. Give one of the keycloak realm's configuration to quarkus.
  3. Set quarkus.oidc.token.issuer in application.properties to any.
  4. Try to send a request to your application with a realm jwt token other than you configured for.

Output of uname -a or ver

Linux hachiko 5.15.0-56-generic #62-Ubuntu SMP Tue Nov 22 19:54:14 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

openjdk version "11.0.17" 2022-10-18

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.9.2.Final

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

No response

@Mert18 Mert18 added the kind/bug Something isn't working label Dec 14, 2022
@sberyozkin sberyozkin added area/oidc and removed kind/bug Something isn't working labels Dec 14, 2022
@sberyozkin
Copy link
Member

Hi @Mert18 It is not really a bug - the issuer property is about verifying the issuer claim only. Each realm though has its own set of verification keys.

Multi-tenancy configuration is the way to go, I understand you have realms created dynamically, changed often, so the static configuration as shown in https://quarkus.io/guides/security-openid-connect-multitenancy#configuring-the-application would not suit.

In such cases https://quarkus.io/guides/security-openid-connect-multitenancy#tenant-config-resolver is the way to go.
Given a request context, you can check the request properties and provide a realm specific configuration dynamically - such a configuration will only be resolved once so the performance won't be impacted.
If requests to the same URL address may involve multiple realms, i.e, request HTTP URL properties are not enough to distinguish between the realms, then get a bearer token from the Authorization header, do io.quarkus.oidc.runtime.OidcUtils#decodeJwtContext to get claims, and then create a right configuration to get this token verified.

HTH

@sberyozkin
Copy link
Member

sberyozkin commented Dec 14, 2022

I'll keep this issue open though, I'd like to think if it makes sense to ship a tenant resolver working with Keycloak doing exactly what is described above - or more likely - document an example

@sberyozkin
Copy link
Member

Hi @Mert18 I've been thinking about the idea of shipping such a TenantConfigResolver which would save users from typing some code where tokens from multiple realms must be supported without having to configure it - but then I've realized it would pose a serious risk if we support something like this:

@ApplicationScoped
public class KeycloakTenantConfigResolver implements TenantConfigResolver {

...
String token = getTokenFromAuthorizationHeader();
JsonObject jwtClaims = OidcUtils.decodeJwtContext();
// For Keycloak the issuer will be set to a specific realm URL
String issuer = jwtClaims.getString("iss");

OidcTenantConfig config = new OidcTenantConfig();
config.setAuthServerUrl(issuer);
return config;
}

because what happens here is that a token input (value of the issuer claim) is used to setup a Keycloak connection dynamically, which will be used to pull the verification keys to verify the token and if the token is valid - let the request go.

The problem here is that the attacker can send a token with the bogus issuer value pointing to some website which will provide public keys verifying this token, and the request goes ahead without Keycloak even being involved.

So I'm afraid we can't do it. Therefore, please try static multi-tenancy config, a number of realms should not be open-ended I guess, or indeed try a custom KeycloakTenantConfigResolver which would be more strict (ex, make sure the issuer URL is from the domain you are aware of, etc) - but would create the config dynamically, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants