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

OIDC - NullPointerException #26236

Closed
beniaminp opened this issue Jun 20, 2022 · 26 comments · Fixed by #26295
Closed

OIDC - NullPointerException #26236

beniaminp opened this issue Jun 20, 2022 · 26 comments · Fixed by #26295

Comments

@beniaminp
Copy link

beniaminp commented Jun 20, 2022

Hello!

I am using quarkus:2.9.2.Final and configured oidc with the following properties:

quarkus.oidc.enabled=true
quarkus.oidc.discovery-enabled=false
quarkus.oidc.authentication.user-info-required=true
quarkus.oidc.roles.role-claim-path=roles
quarkus.oidc.proxy.host=my-proxy-host
quarkus.oidc.proxy.port=my-proxy-port
quarkus.oidc.auth-server-url=my-server-url
quarkus.oidc.client-id=my-client-id
quarkus.oidc.credentials.secret=my-client-secret
quarkus.oidc.token-path=/oauth/token
quarkus.oidc.authorization-path=/oauth/authorize
quarkus.oidc.introspection-path=/introspect
quarkus.oidc.user-info-path=/userinfo
quarkus.oidc.authentication.response_type=token
quarkus.oidc.authentication.add-openid-scope=false
quarkus.log.min-level=DEBUG
quarkus.log.category."io.quarkus.oidc".level=DEBUG

with all the variables for url, client and secret configured.

When I am trying to start it I get the following error:


- ERROR [io.qua.run.Application] (Quarkus Main Thread) Failed to start application (with profile dev): java.lang.NullPointerException
- 	at io.quarkus.oidc.runtime.DefaultTenantConfigResolver_Bean.create(Unknown Source)
- 	at io.quarkus.oidc.runtime.DefaultTenantConfigResolver_Bean.create(Unknown Source)
- 	at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:111)
- 	at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35)
- 	at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:32)
- 	at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
- 	at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
- 	at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:32)
- 	at io.quarkus.arc.impl.ClientProxies.getApplicationScopedDelegate(ClientProxies.java:19)
- 	at io.quarkus.oidc.runtime.DefaultTenantConfigResolver_ClientProxy.arc$delegate(Unknown Source)
- 	at io.quarkus.oidc.runtime.DefaultTenantConfigResolver_ClientProxy.setSecurityEventObserved(Unknown Source)
- 	at io.quarkus.oidc.runtime.OidcRecorder.setSecurityEventObserved(OidcRecorder.java:227)
- 	at io.quarkus.deployment.steps.OidcBuildStep$findSecurityEventObservers1053450247.deploy_0(Unknown Source)
- 	at io.quarkus.deployment.steps.OidcBuildStep$findSecurityEventObservers1053450247.deploy(Unknown Source)
- 	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
- 	at io.quarkus.runtime.Application.start(Application.java:101)
- 	at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:103)
- 	at io.quarkus.runtime.Quarkus.run(Quarkus.java:67)
- 	at io.quarkus.runtime.Quarkus.run(Quarkus.java:41)
- 	at io.quarkus.runtime.Quarkus.run(Quarkus.java:120)
- 	at com.company.Main.main(Main.java:20)
- 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
- 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
- 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
- 	at io.quarkus.runner.bootstrap.StartupActionImpl$1.run(StartupActionImpl.java:103)

I do not event know where to start to investigate it.
One thing that I noticed was that if I disabled the oidc, the application starts without error (if I set quarkus.oidc.enabled=false)

And clue from where to start?

Thank you!

@quarkus-bot
Copy link

quarkus-bot bot commented Jun 20, 2022

/cc @pedroigor, @sberyozkin

@sberyozkin
Copy link
Member

@beniaminp Hi, does it start in JVM mode, with java -jar target/quarkus-app/quarkus-run.jar ?

@beniaminp
Copy link
Author

@sberyozkin I am using the idea intelij quarkus plugin to start it.
Thanks!

@sberyozkin
Copy link
Member

@beniaminp I'd like to understand if it is specific to dev mode or not, since there is Failed to start application (with profile dev):...

So please try to build the application from the command line and check if it starts in the prod profile.
Or create a reproducer - it is hard to advise anything meaningful otherwise

@beniaminp
Copy link
Author

Hi @sberyozkin. It is happening in debug mode. Unfortunately I cannot reproduce it in a simple project, it is happening on a project with closed sources and in dev mode. After some debugging, I am getting the following exception:
Error injecting boolean io.quarkus.oidc.runtime.DefaultTenantConfigResolver.enableHttpForwardedPrefix and same NullPointerException. I have set the enableHttpForwardedPrefix to true / false but there is no difference, the same error.

I will run it in production mode and let you know how is going.

Thank you!

@beniaminp
Copy link
Author

It looks like that in the prod mode I am having the same issue. If I disable the oidc everything works (except the authentication / authorization)

Thanks!

@mkouba
Copy link
Contributor

mkouba commented Jun 21, 2022

@mkouba Hi Martin, can you please check the above stacktrace, may be you can spot something, the trace includes https://github.com/quarkusio/quarkus/blob/2.9.2.Final/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java#L225 which goes to https://github.com/quarkusio/quarkus/blob/2.9.2.Final/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/DefaultTenantConfigResolver.java#L164

I don't see anything special. The NPE comes from the DefaultTenantConfigResolver_Bean.create() which looks like:

public DefaultTenantConfigResolver create(final CreationalContext creationalContext) {
		final DefaultTenantConfigResolver defaultTenantConfigResolver = new DefaultTenantConfigResolver();
		try {
			final InjectableReferenceProvider value = this.injectProviderSupplier1.get();
			defaultTenantConfigResolver.enableHttpForwardedPrefix = (boolean) value
					.get((CreationalContext) CreationalContextImpl.child((InjectableReferenceProvider) value,
							creationalContext));
		} catch (RuntimeException ex) {
			throw new RuntimeException(
					"Error injecting boolean io.quarkus.oidc.runtime.DefaultTenantConfigResolver.enableHttpForwardedPrefix",
					ex);
		}
		try {
			final InjectableReferenceProvider value2 = this.injectProviderSupplier2.get();
			defaultTenantConfigResolver.securityEvent = (Event) value2.get((CreationalContext) CreationalContextImpl
					.child((InjectableReferenceProvider) value2, creationalContext));
		} catch (RuntimeException ex2) {
			throw new RuntimeException(
					"Error injecting javax.enterprise.event.Event<io.quarkus.oidc.SecurityEvent> io.quarkus.oidc.runtime.DefaultTenantConfigResolver.securityEvent",
					ex2);
		}
		try {
			final InjectableReferenceProvider value3 = this.injectProviderSupplier3.get();
			defaultTenantConfigResolver.tenantConfigBean = (TenantConfigBean) value3
					.get((CreationalContext) CreationalContextImpl.child((InjectableReferenceProvider) value3,
							creationalContext));
		} catch (RuntimeException ex3) {
			throw new RuntimeException(
					"Error injecting io.quarkus.oidc.runtime.TenantConfigBean io.quarkus.oidc.runtime.DefaultTenantConfigResolver.tenantConfigBean",
					ex3);
		}
		try {
			final InjectableReferenceProvider value4 = this.injectProviderSupplier4.get();
			defaultTenantConfigResolver.tenantConfigResolver = (Instance) value4
					.get((CreationalContext) CreationalContextImpl.child((InjectableReferenceProvider) value4,
							creationalContext));
		} catch (RuntimeException ex4) {
			throw new RuntimeException(
					"Error injecting javax.enterprise.inject.Instance<io.quarkus.oidc.TenantConfigResolver> io.quarkus.oidc.runtime.DefaultTenantConfigResolver.tenantConfigResolver",
					ex4);
		}
		try {
			final InjectableReferenceProvider value5 = this.injectProviderSupplier5.get();
			defaultTenantConfigResolver.tenantResolver = (Instance) value5.get((CreationalContext) CreationalContextImpl
					.child((InjectableReferenceProvider) value5, creationalContext));
		} catch (RuntimeException ex5) {
			throw new RuntimeException(
					"Error injecting javax.enterprise.inject.Instance<io.quarkus.oidc.TenantResolver> io.quarkus.oidc.runtime.DefaultTenantConfigResolver.tenantResolver",
					ex5);
		}
		try {
			final InjectableReferenceProvider value6 = this.injectProviderSupplier6.get();
			defaultTenantConfigResolver.tokenIntrospectionCache = (Instance) value6
					.get((CreationalContext) CreationalContextImpl.child((InjectableReferenceProvider) value6,
							creationalContext));
		} catch (RuntimeException ex6) {
			throw new RuntimeException(
					"Error injecting javax.enterprise.inject.Instance<io.quarkus.oidc.TokenIntrospectionCache> io.quarkus.oidc.runtime.DefaultTenantConfigResolver.tokenIntrospectionCache",
					ex6);
		}
		try {
			final InjectableReferenceProvider value7 = this.injectProviderSupplier7.get();
			defaultTenantConfigResolver.tokenStateManager = (Instance) value7
					.get((CreationalContext) CreationalContextImpl.child((InjectableReferenceProvider) value7,
							creationalContext));
		} catch (RuntimeException ex7) {
			throw new RuntimeException(
					"Error injecting javax.enterprise.inject.Instance<io.quarkus.oidc.TokenStateManager> io.quarkus.oidc.runtime.DefaultTenantConfigResolver.tokenStateManager",
					ex7);
		}
		try {
			final InjectableReferenceProvider value8 = this.injectProviderSupplier8.get();
			defaultTenantConfigResolver.userInfoCache = (Instance) value8.get((CreationalContext) CreationalContextImpl
					.child((InjectableReferenceProvider) value8, creationalContext));
		} catch (RuntimeException ex8) {
			throw new RuntimeException(
					"Error injecting javax.enterprise.inject.Instance<io.quarkus.oidc.UserInfoCache> io.quarkus.oidc.runtime.DefaultTenantConfigResolver.userInfoCache",
					ex8);
		}
		defaultTenantConfigResolver.verifyResolvers();
		return defaultTenantConfigResolver;
	}

@sberyozkin
Copy link
Member

Thanks @beniaminp @mkouba

@beniaminp I honestly don't know how I can help without a reproducer. Can you create a HelloWorld endpoint protected with quarkus-oidc with the same configuration ?

@beniaminp
Copy link
Author

Hey @sberyozkin . I tried in a new project with the same settings and it apparently work. Probably is something about my specific project (it is quite big).
I am trying to debug it and to find the root cause of NPE. I will update here all the progress, maybe it can help.

Thanks!

@sberyozkin
Copy link
Member

@beniaminp Sounds good, thanks, yes, please try to narrow down

@beniaminp
Copy link
Author

Hey @sberyozkin. I upgraded to java16 an run with -XX:+ShowCodeDetailsInExceptionMessages and I got an explanation for the NPE.
Does this mean something for you?
(Quarkus Main Thread) Failed to start application (with profile dev): java.lang.NullPointerException: Cannot invoke "java.lang.Boolean.booleanValue()" because "<local6>" is null

I think that it is related to quarkus.http.proxy.enable-forwarded-prefix=false, but I am not 100% sure.
Also, I cannot find the DefaultTenantConfigResolver_Bean.create() in quarkus repo.

Thanks!

@mkouba
Copy link
Contributor

mkouba commented Jun 22, 2022

Also, I cannot find the DefaultTenantConfigResolver_Bean.create() in quarkus repo.

It should be located in target/quarkus-app/quarkus/generated-bytecode.jar...

@beniaminp
Copy link
Author

Thanks @mkouba !

Also, when the Arc container is trying to get the DefaultTenantConfigResolver it has an error:
Method threw 'java.lang.RuntimeException' exception. Cannot evaluate io.quarkus.oidc.runtime.DefaultTenantConfigResolver_ClientProxy.toString(), on OidcRecorder.setSecurityEventObserved for call: DefaultTenantConfigResolver bean = Arc.container().instance(DefaultTenantConfigResolver.class).get(); and when it is trying to set the security event observed I get : Error injecting boolean io.quarkus.oidc.runtime.DefaultTenantConfigResolver.enableHttpForwardedPrefix.

Maybe you can see the problem faster then me :).

Thanks!

@beniaminp
Copy link
Author

The problem looks to be in public DefaultTenantConfigResolver create(final CreationalContext creationalContext)
at:

final DefaultTenantConfigResolver defaultTenantConfigResolver = new DefaultTenantConfigResolver(); try { final InjectableReferenceProvider value = this.injectProviderSupplier1.get(); defaultTenantConfigResolver.enableHttpForwardedPrefix = (boolean) value .get((CreationalContext) CreationalContextImpl.child((InjectableReferenceProvider) value, creationalContext)); } catch (RuntimeException ex) { throw new RuntimeException( "Error injecting boolean io.quarkus.oidc.runtime.DefaultTenantConfigResolver.enableHttpForwardedPrefix", ex); }

Somehow enableHttpForwardedPrefix cannot be injected and
value .get((CreationalContext) CreationalContextImpl.child((InjectableReferenceProvider) value, creationalContext))

cannot be converted to boolean because some <local6> is null

@mkouba
Copy link
Contributor

mkouba commented Jun 22, 2022

<local6> is null probaby means that there is a constructor which accepts a boolean parameter but a null argument is passed instead (i.e. autoboxing fails).

@mkouba
Copy link
Contributor

mkouba commented Jun 22, 2022

@beniaminp just out of curiosity, could you try to replace @ConfigProperty(name = "quarkus.http.proxy.enable-forwarded-prefix") boolean enableHttpForwardedPrefix with @Inject HttpConfiguration httpConfig and httpConfig.proxy.enableForwardedPrefix?

@mkouba
Copy link
Contributor

mkouba commented Jun 22, 2022

@sberyozkin I think that io.quarkus.oidc.deployment.OidcBuildStep.findSecurityEventObservers() should consume the RuntimeConfigSetupCompleteBuildItem to ensure the runtime config is set up (because DefaultTenantConfigResolver.enableHttpForwardedPrefix is a runtime config property). I'll send a PR shortly.

@sberyozkin
Copy link
Member

sberyozkin commented Jun 22, 2022

Thanks, I can replace it as Martin suggested if it can help to fix it

@mkouba
Copy link
Contributor

mkouba commented Jun 22, 2022

Thanks, I can replace it as Martin suggested if it can help to fix it

Actually, I don't think this would help. Testing my fix for #26236 (comment) right now...

mkouba added a commit to mkouba/quarkus that referenced this issue Jun 22, 2022
- this build step should consume RuntimeConfigSetupCompleteBuildItem
because DefaultTenantConfigResolver injects a runtime config property
- resolves quarkusio#26236
mkouba added a commit to mkouba/quarkus that referenced this issue Jun 22, 2022
- this build step should consume RuntimeConfigSetupCompleteBuildItem
because DefaultTenantConfigResolver injects a runtime config property
- resolves quarkusio#26236
mkouba added a commit to mkouba/quarkus that referenced this issue Jun 22, 2022
- this build step should consume RuntimeConfigSetupCompleteBuildItem
because DefaultTenantConfigResolver injects a runtime config property
- resolves quarkusio#26236
@beniaminp
Copy link
Author

I tested the change and unfortunately it did not work, I get the same error.
The only way to pass above this step was to do some temporary changes in DefaultTenantConfigResolver:
@Inject @ConfigProperty(name = "quarkus.http.proxy.enable-forwarded-prefix", defaultValue = "false") Optional<Boolean> enableHttpForwardedPrefix;

and
boolean isEnableHttpForwardedPrefix() { return enableHttpForwardedPrefix.orElse(false); }

I am not sure why it cannot find the ConfigProperty yet.

Thanks!

@mkouba
Copy link
Contributor

mkouba commented Jun 24, 2022

I tested the change and unfortunately it did not work, I get the same error.

That's not good :-(.

We really need a reproducer. @beniaminp What extensions does your app use?

@beniaminp
Copy link
Author

I tried to reproduce it on an empty project, but everything works fine.
In this project, I am migrating an old java ee project to quarkus. We did all the changes in order for quarkus to run and this is the only thing that is not working. If I disable the oidc, everything works fine.
I did the changes on quarkus-oidc runtime on DefaultTenantConfigResolver and now it is working, but I have to check if it still takes into account the enableHttpForwardedPrefix property, because my guess is that it will always be false.

@mkouba
Copy link
Contributor

mkouba commented Jun 24, 2022

I tried to reproduce it on an empty project, but everything works fine.

That's unfortunate. I'm afraid we can't do more without a reproducer...

I did the changes on quarkus-oidc runtime on DefaultTenantConfigResolver and now it is working, but I have to check if it still takes into account the enableHttpForwardedPrefix property, because my guess is that it will always be false.

Yes, you would have to use programmatic lookup and lazy injection, i.e. something like @ConfigProperty(name = "quarkus.http.proxy.enable-forwarded-prefix") Instance<Boolean> enableHttpForwardedPrefix and then enableHttpForwardedPrefix.get().

@quarkus-bot quarkus-bot bot added this to the 2.11 - main milestone Jun 24, 2022
@beniaminp
Copy link
Author

We finally manage to find the problem.
After we remove the dependency:
<dependency> <groupId>org.eclipse.microprofile.config</groupId> <artifactId>microprofile-config-api</artifactId> <version>3.0.1</version> </dependency>
we got no more NPE.

It looks like quarkus does not play nice with it. At least, now we know :).

@mkouba
Copy link
Contributor

mkouba commented Jun 27, 2022

Ah, that's some good news! Yes, quarkus is using org.eclipse.microprofile.config:microprofile-config-api:2.0.1 and you should not bring any MP dependencies manually but rely on the versions included by quarkus extensions instead.

@gsmet gsmet modified the milestones: 2.11 - main, 2.10.1.Final Jun 28, 2022
gsmet pushed a commit to gsmet/quarkus that referenced this issue Jun 28, 2022
- this build step should consume RuntimeConfigSetupCompleteBuildItem
because DefaultTenantConfigResolver injects a runtime config property
- resolves quarkusio#26236

(cherry picked from commit b43a7be)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants