Re: Cannot invoke "org.eclipse.microprofile.auth.LoginConfig.authMethod()" because "loginConfig" is null
Richard Zowalla <[email protected]> Sat, 12 Jul 2025 14:02:21 +0200
| Newsgroups | gmane.comp.java.openejb.user |
|---|---|
| Message-ID | <DF867FC3-9B3D-4089-8474-41863DB6DC4B__9321.49581364996$1752321800$gmane$org@apache.org> |
Hi, I think this is were things are going to be complicated ;-)=20 Hard to say what the reason could possibly be in your EAR setup. =46rom what I remember is, that EARs make things always a bit more = complicated due to the special classloader hierarchies involved. I would double check, that no (api) libs provide by the container are = available in the WAR archives, EJB modules or in the shared libs of the = EAR. Next step would be to remote debug the application for a specific = request to see, what actually goes wrong on the container / = configuration side of things. Gru=C3=9F Richard > Am 12.07.2025 um 11:08 schrieb Java Entwicklung = <[email protected]>: >=20 > Hello Richard, >=20 > Yes indeed, that was the problem! It starts just fine on the demo app = and > with my keycloak details it authenticates and authorizes as expected. > However, in the real app where I need this, it is giving me 403 = (meaning > authentication worked but "admin-role" is somehow still = unrecognised).. >=20 > So far I developed and used my custom app without Keycloak. I could > delegate the requests to the app-core without issues (because my proxy = war > app was already there - within the EAR of that backend system. > But now, when I'm touching the roles, it seems not to recognise my = Keycloak > roles ("admin-role", "user-role") and gives me 403. >=20 > ------ here's what I used to ask ChatGPT about the issue but it wasn't = much > of a help ---- >=20 > My backend app is deployed to TomEE 10 as an EAR. That ear consists of > several WARs, most important ones being: > * app-core.war --> the core of the backend > * app-rest.war --> the rest layer > * my-custom-proxy-app.war --> I added this as proxy layer; external = backend > clients (like mobile apps, web apps, desktop apps, etc. send their = requests > to this app and it then delegates to the core backend >=20 > The backend app itself has its own java/tomcat security layer, = consisting > of realms, policies, roles, users, etc. >=20 > Now, I want my client apps AND my proxy app (my-custom-proxy-app.war) = to > use keycloak for authentication and authorization. On the client apps' = end > it is working and the requests are being sent with a valid bearer = token. >=20 > In TomEE I'm using MP-JWT and it is able to confirm validity of the = token > so a request to a protected resource doesn't return 401 (sign that it > authenticated successfully) - but rather it is returning 403, meaning = that > the role ("admin-role") that is contained in my Keycloak's token is = not > recognized (the role is correctly included under "groups" - it's done = on > Keycloak level and is the same keycloak instance I used with the demo = app, > where it worked). >=20 > Important: > * I don't need my "admin-role" available across other WARs - just in = this > my-custom-proxy-app.war > * role in token is correctly configured - I built a demo app where a = single > WAR is deployed to TomEE and I get 200 for a protected resource > * everything else, including annotations and MP config is set exactly = how > it is set up in the demo app > * I can see backend's roles being defined in > <EAR>/META-INF/application.xml, and then once again in > <EAR>/app-core/WEB-INF/web.xml -- I tried adding "admin-role" role > definition to both of those places but it changed nothing. >=20 > That means, somehow the whole backend application expects my = "admin-role" > from the token to be part of backend app's security realm. The thing = is: i > don't know how everything works in such a set up. > --------------------------------------------------------------------- >=20 > I hope this sheds some light on my setup and you will know what the = issue > is. >=20 >=20 > On Fri, 11 Jul 2025 at 20:03, Richard Zowalla <[email protected]> wrote: >=20 >> Hi, >>=20 >> Had a quick look at your example: >> https://github.com/javac9/tomee-with-jwt-demo >>=20 >> You shouldn=E2=80=99t bundle the API=E2=80=99s in your web app. In = TomEE, these libs are >> shipped with the container, i.e >> should be in compileOnly scope: >>=20 >> implementation("org.apache.tomee:jakartaee-api:10.0") >>=20 >>=20 >> = implementation("org.eclipse.microprofile.jwt:microprofile-jwt-auth-api:2.1= =E2=80=9C) >>=20 >> If you change that and do a full WAR rebuild, the web app will = deploy: >>=20 >> tomee | 11-Jul-2025 18:00:33.859 INFO [main] >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints REST >> Application: http://localhost:8080/demoapp/api -> >> com.example.tomeewithjwtdemo.HelloApplication@5fd8302e >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints >> Service URI: http://localhost:8080/demoapp/api/health -> Pojo >> org.apache.tomee.microprofile.health.MicroProfileHealthChecksEndpoint >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints >> GET http://localhost:8080/demoapp/api/health -> = Response >> getChecks() >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints >> GET http://localhost:8080/demoapp/api/health/live -> = Response >> getLiveChecks() >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints >> GET http://localhost:8080/demoapp/api/health/ready -> = Response >> getReadyChecks() >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints >> GET http://localhost:8080/demoapp/api/health/started -> = Response >> getStartedChecks() >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints >> Service URI: http://localhost:8080/demoapp/api/v1 -> Pojo >> com.example.tomeewithjwtdemo.HelloResource >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints >> GET http://localhost:8080/demoapp/api/v1/admin -> String >> helloAdmin() >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints >> GET http://localhost:8080/demoapp/api/v1/user -> String >> hello() >> tomee | 11-Jul-2025 18:00:33.880 INFO [main] >> java.lang.reflect.Method.invoke Deployment of web application archive >> [/usr/local/tomee/webapps/demoapp.war] has finished in [1,420] ms >>=20 >> Since I don=E2=80=99t have a key cloak setup available, it will = subsequently fail >> ;-) >>=20 >> Gru=C3=9F >> Richard >>=20 >>=20 >>> Am 11.07.2025 um 14:54 schrieb Java Entwicklung = <[email protected]>: >>>=20 >>> ``` >>> # Tested with: >>> tomee docker image: tomee:plus >>> org.eclipse.microprofile.jwt:microprofile-jwt-auth-api:2.1 >>>=20 >>> # but same is with: >>> tomee docker image: tomee:10.1-jre21-plus >>> org.eclipse.microprofile.jwt:microprofile-jwt-auth-api:2.2-RC1 >>> ``` >>>=20 >>> Hello, >>>=20 >>> I created a demo Jakarta EE 10 app and configured it so it = authenticates >>> incoming requests to my protected resource against my Keycloak = instance. >>>=20 >>> It works successfully with Payara Micro 6 but with TomEE 10.0 (which = is >>> what I need and have to use) it fails on startup with the following: >>> ``` >>> 11-Jul-2025 11:55:42.801 WARNING [main] >>> org.apache.batchee.container.services.ServicesManager.init You = didn't >>> specify org.apache.batchee.jmx.application and JMX is already = registered, >>> skipping >>> 2025-07-11T11:55:42.804794711Z 11-Jul-2025 11:55:42.804 INFO [main] >>> org.apache.openejb.assembler.classic.Assembler.createApplication = Deployed >>> Application(path=3D/usr/local/tomee/webapps/demoapp) >>> 2025-07-11T11:55:43.426149580Z 11-Jul-2025 11:55:43.425 INFO [main] >>> org.apache.myfaces.webapp.MyFacesContainerInitializer.onStartup = Using >>> org.apache.myfaces.webapp.MyFacesContainerInitializer >>> 2025-07-11T11:55:43.614818412Z 11-Jul-2025 11:55:43.614 INFO [main] >>> org.apache.myfaces.webapp.MyFacesContainerInitializer.onStartup = Added >>> FacesServlet with mappings=3D[/faces/*, *.jsf, *.faces, *.xhtml] >>> 2025-07-11T11:55:43.628173897Z 11-Jul-2025 11:55:43.626 SEVERE = [main] >>> java.lang.reflect.Method.invoke Error deploying web application = archive >>> [/usr/local/tomee/webapps/demoapp.war] >>> 2025-07-11T11:55:43.628209564Z java.lang.IllegalStateException: = Error >>> starting child >>> 2025-07-11T11:55:43.628212292Z at >>>=20 >> = org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java= :602) >>> 2025-07-11T11:55:43.628214272Z at >>> = org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:571) >>> 2025-07-11T11:55:43.628215708Z at >>> = org.apache.catalina.core.StandardHost.addChild(StandardHost.java:654) >>> 2025-07-11T11:55:43.628217070Z at >>> = org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:965) >>> 2025-07-11T11:55:43.628218545Z at >>>=20 >> = org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1903)= >>> 2025-07-11T11:55:43.628219991Z at >>> = java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown >>> Source) >>> 2025-07-11T11:55:43.628221298Z at >>> java.base/java.util.concurrent.FutureTask.run(Unknown Source) >>> 2025-07-11T11:55:43.628222601Z at >>>=20 >> = org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecuto= rService.java:75) >>> 2025-07-11T11:55:43.628224008Z at >>> = java.base/java.util.concurrent.AbstractExecutorService.submit(Unknown >>> Source) >>> 2025-07-11T11:55:43.628236311Z at >>> = org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:769) >>> 2025-07-11T11:55:43.628238350Z at >>> = org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:420) >>> 2025-07-11T11:55:43.628239666Z at >>> org.apache.catalina.startup.HostConfig.start(HostConfig.java:1621) >>> 2025-07-11T11:55:43.628241335Z at >>>=20 >> = org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:303)= >>> 2025-07-11T11:55:43.628255587Z at >>>=20 >> = org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.ja= va:109) >>> 2025-07-11T11:55:43.628256899Z at >>>=20 >> = org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java= :389) >>> 2025-07-11T11:55:43.628258590Z at >>> = org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:336) >>> 2025-07-11T11:55:43.628259958Z at >>>=20 >> = org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:77= 6) >>> 2025-07-11T11:55:43.628261506Z at >>>=20 >> = org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:772)= >>> 2025-07-11T11:55:43.628263034Z at >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) >>> 2025-07-11T11:55:43.628274187Z at >>>=20 >> = org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:= 1203) >>> 2025-07-11T11:55:43.628275693Z at >>>=20 >> = org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:= 1193) >>> 2025-07-11T11:55:43.628277030Z at >>> java.base/java.util.concurrent.FutureTask.run(Unknown Source) >>> 2025-07-11T11:55:43.628280369Z at >>>=20 >> = org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecuto= rService.java:75) >>> 2025-07-11T11:55:43.628281839Z at >>> = java.base/java.util.concurrent.AbstractExecutorService.submit(Unknown >>> Source) >>> 2025-07-11T11:55:43.628283322Z at >>>=20 >> = org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:74= 9) >>> 2025-07-11T11:55:43.628284925Z at >>>=20 >> = org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:= 203) >>> 2025-07-11T11:55:43.628286472Z at >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) >>> 2025-07-11T11:55:43.628287734Z at >>>=20 >> = org.apache.catalina.core.StandardService.startInternal(StandardService.jav= a:412) >>> 2025-07-11T11:55:43.628289236Z at >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) >>> 2025-07-11T11:55:43.628290566Z at >>>=20 >> = org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:= 870) >>> 2025-07-11T11:55:43.628292404Z at >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) >>> 2025-07-11T11:55:43.628293861Z at >>> org.apache.catalina.startup.Catalina.start(Catalina.java:761) >>> 2025-07-11T11:55:43.628295318Z at >>> = java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown >>> Source) >>> 2025-07-11T11:55:43.628301199Z at >>> java.base/java.lang.reflect.Method.invoke(Unknown Source) >>> 2025-07-11T11:55:43.628302697Z at >>> org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345) >>> 2025-07-11T11:55:43.628304266Z at >>> org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476) >>> 2025-07-11T11:55:43.628305690Z Caused by: >>> org.apache.catalina.LifecycleException: Failed to start component >>>=20 >> = [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/demoapp= ]] >>> 2025-07-11T11:55:43.628307498Z at >>>=20 >> = org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBa= se.java:406) >>> 2025-07-11T11:55:43.628309026Z at >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:179) >>> 2025-07-11T11:55:43.628310551Z at >>>=20 >> = org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java= :599) >>> 2025-07-11T11:55:43.628312065Z ... 35 more >>> 2025-07-11T11:55:43.628313380Z Caused by: = java.lang.NullPointerException: >>> Cannot invoke = "org.eclipse.microprofile.auth.LoginConfig.authMethod()" >>> because "loginConfig" is null >>> 2025-07-11T11:55:43.628315144Z at >>>=20 >> = org.apache.tomee.microprofile.jwt.MPJWTInitializer.onStartup(MPJWTInitiali= zer.java:45) >>> 2025-07-11T11:55:43.628316658Z at >>>=20 >> = org.apache.catalina.core.StandardContext.startInternal(StandardContext.jav= a:4464) >>> 2025-07-11T11:55:43.628320249Z at >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) >>> 2025-07-11T11:55:43.628321622Z ... 36 more >>> 2025-07-11T11:55:43.632485224Z 11-Jul-2025 11:55:43.632 INFO [main] >>> java.lang.reflect.Method.invoke Deployment of web application = archive >>> [/usr/local/tomee/webapps/demoapp.war] has finished in [3,177] ms >>> 2025-07-11T11:55:43.637611803Z 11-Jul-2025 11:55:43.637 INFO [main] >>> java.lang.reflect.Method.invoke Starting ProtocolHandler >> ["http-nio-8080"] >>> 2025-07-11T11:55:43.649430271Z 11-Jul-2025 11:55:43.649 INFO [main] >>> java.lang.reflect.Method.invoke Server startup in [3311] = milliseconds >>> ``` >>> Here's how I configured it: >>>=20 >>> ``` >>> @ApplicationScoped >>> @ApplicationPath("/api") >>> @LoginConfig(authMethod=3D"MP-JWT") >>> @DeclareRoles({ >>> "admin-role", >>> "user-role" >>> }) >>> public class HelloApplication extends Application { >>>=20 >>> } >>>=20 >>> // is a separate class >>> @Path("/v1") >>> @Produces("text/plain") >>> public class HelloResource { >>>=20 >>> @GET >>> @Path("/admin") >>> @RolesAllowed("admin-role") >>> public String helloAdmin() { >>> return "Hello, Admin!"; >>> } >>>=20 >>> @GET >>> @Path("/user") >>> public String hello() { >>> return "Hello, user!"; >>> } >>>=20 >>> } >>> ``` >>>=20 >>> In `src/main/resources/META-INF/microprofile-config.properties` I = have: >>> ``` >>> # JWT Configuration >>> mp.jwt.verify.issuer=3Dhttp://auth.localhost:8090/realms/myrealm >>> mp.jwt.verify.publickey.location=3D >>> = http://auth.localhost:8090/realms/myrealm/protocol/openid-connect/certs >>> ``` >>> and my `src/main/webapp/WEB-INF/web.xml` contains: >>> ``` >>> <?xml version=3D"1.0" encoding=3D"UTF-8"?> >>> <web-app xmlns=3D"https://jakarta.ee/xml/ns/jakartaee" >>> xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance" >>> xsi:schemaLocation=3D"https://jakarta.ee/xml/ns/jakartaee >>> https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" >>> version=3D"6.0"> >>>=20 >>>=20 >>> </web-app> >>> ``` >>>=20 >>> I run gradle war, mount it to my tomee container's deployment dir = and >> start >>> it. Again, this exact setup worked perfectly with Payara - the idea = was >> to >>> make sure the config is correct before trying to solve startup issue = in >>> TomEE (sure, TomEE might require something differently). >>>=20 >>>=20 >>> Note that removing `@LoginConfig(authMethod=3D"MP-JWT")` annotation = on the >>> class and using: >>> ``` >>> <login-config> >>> <auth-method>MP-JWT</auth-method> >>> </login-config> >>> ``` >>> doesn't have the same effect! There is no such startup error but all >>> resources return `404 Not found`. >>>=20 >>> Also note that I have tested with various other TomEE flavours of = version >>> 10 - but no difference. >>=20 >>=20