Problems with OIDC Bearer setup

Hi,

I have configured my Geonetwork (v4.4.6) instance to work with OIDC, using Keycloak as IDP. When using the web interface, this works as expected, redirecting to login and back, then creating rows in the Geonetwork DB for user and group based on information from Keycloak.
For instance, if my Keycloak user is named “test-user” and has a role like “test:Reviewer”, this is interpreted correctly and a new user row with name=“test-user” and profile=“Reviewer” is set, as well as the group row “test”. However, with CSW transactions, the same does not work. If a user which has not previously logged in via the web interface, tries to make a request to the csw-publication endpoint, I get the following response:

200 OK
<?xml version="1.0" encoding="UTF-8"?>
<ows:ExceptionReport xmlns:ows="http://www.opengis.net/ows" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2.0" xsi:schemaLocation="http://www.opengis.net/ows http://schemas.opengis.net/ows/1.0.0/owsExceptionReport.xsd">
    <ows:Exception exceptionCode="NoApplicableCode">
        <ows:ExceptionText>Cannot process transaction: Service not allowed</ows:ExceptionText>
    </ows:Exception>
</ows:ExceptionReport>

Whereas if I’ve logged in once via web, then make a request to csw-publication, it works as expected, setting group and user ownership of the metadata record. Is this expected behaviour, or am I missing something?

From the logs (see below), it looks like the intended behaviour is to add the user, but it seems like this step fails. The metadata record gets inserted, but not indexed, and ownership (group/user) is NULL.

Best regards,
Pål Marius

My ENV-vars that I use for OIDC bearer setup:

GEONETWORK_SECURITY_TYPE: openidconnectbearer
OPENIDCONNECT_CLIENTSECRET: <my-secret>
OPENIDCONNECT_CLIENTID: <my-client-id>
OPENIDCONNECT_SERVERMETADATA_CONFIG_URL: https://<my-keycloak-server>/realms/<my-realm>/.well-known/openid-configuration
OPENIDCONNECT_IDTOKENROLELOCATION: resource_access.<my-client-id>.roles
OPENIDCONNECT_LOGSENSITIVE_INFO: "true"

Excerpt from Geonetworks logs:

2025-03-24 14:22:10 2025-03-24T14:22:10,226 DEBUG [geonetwork.security] - Adding a new user: test@example.com(0) - RegisteredUser
2025-03-24 14:22:10 2025-03-24T14:22:10,226 DEBUG [geonetwork.security] - Identified group:profile (test:Reviewer) from user token.
2025-03-24 14:22:10 2025-03-24T14:22:10,227 DEBUG [geonetwork.security] - Identified group:profile (test:Reviewer) from user token.
2025-03-24 14:22:10 2025-03-24T14:22:10,233 DEBUG [org.hibernate.SQL] - select distinct usergroup0_.groupId as col_0_0_ from UserGroups usergroup0_ where usergroup0_.profile=? and usergroup0_.userId=0
2025-03-24 14:22:10 2025-03-24T14:22:10,237 ERROR [geonetwork.csw] - Cannot process transaction
2025-03-24 14:22:10 2025-03-24T14:22:10,239 ERROR [geonetwork.csw] -  (C) StackTrace
2025-03-24 14:22:10 ServiceNotAllowedEx : Service not allowed
2025-03-24 14:22:10     at org.fao.geonet.kernel.datamanager.base.BaseMetadataOperations.checkOperationPermission(BaseMetadataOperations.java:241)
2025-03-24 14:22:10     at org.fao.geonet.kernel.datamanager.base.BaseMetadataOperations.getOperationAllowedToAddInternal(BaseMetadataOperations.java:213)
2025-03-24 14:22:10     at org.fao.geonet.kernel.datamanager.base.BaseMetadataOperations.getOperationAllowedToAdd(BaseMetadataOperations.java:202)
2025-03-24 14:22:10     at org.fao.geonet.kernel.datamanager.base.BaseMetadataOperations.setOperation(BaseMetadataOperations.java:150)
2025-03-24 14:22:10     at org.fao.geonet.kernel.datamanager.base.BaseMetadataOperations.setOperation(BaseMetadataOperations.java:124)
2025-03-24 14:22:10     at org.fao.geonet.kernel.DataManager.setOperation(DataManager.java:448)
2025-03-24 14:22:10     at org.fao.geonet.component.csw.Transaction.insertTransaction(Transaction.java:277)
2025-03-24 14:22:10     at org.fao.geonet.component.csw.Transaction.execute(Transaction.java:149)
2025-03-24 14:22:10     at org.fao.geonet.component.csw.CatalogDispatcher.dispatchI(CatalogDispatcher.java:137)
2025-03-24 14:22:10     at org.fao.geonet.component.csw.CatalogDispatcher.dispatch(CatalogDispatcher.java:99)
2025-03-24 14:22:10     at org.fao.geonet.services.main.CswPublicationDispatcher.serviceSpecificExec(CswPublicationDispatcher.java:119)
2025-03-24 14:22:10     at org.fao.geonet.services.NotInReadOnlyModeService.exec(NotInReadOnlyModeService.java:54)
2025-03-24 14:22:10     at jeeves.server.dispatchers.ServiceInfo.execService(ServiceInfo.java:227)
2025-03-24 14:22:10     at jeeves.server.dispatchers.ServiceInfo.noTransactionExec(ServiceInfo.java:142)
2025-03-24 14:22:10     at jeeves.server.dispatchers.ServiceInfo$1.doInTransaction(ServiceInfo.java:121)
2025-03-24 14:22:10     at jeeves.server.dispatchers.ServiceInfo$1.doInTransaction(ServiceInfo.java:118)
2025-03-24 14:22:10     at jeeves.transaction.TransactionManager.runInTransaction(TransactionManager.java:75)
2025-03-24 14:22:10     at jeeves.server.dispatchers.ServiceInfo.execServices(ServiceInfo.java:115)
2025-03-24 14:22:10     at jeeves.server.dispatchers.ServiceManager.dispatch(ServiceManager.java:458)
2025-03-24 14:22:10     at jeeves.server.dispatchers.ServiceManager.dispatch(ServiceManager.java:396)
2025-03-24 14:22:10     at jeeves.server.JeevesEngine.dispatch(JeevesEngine.java:572)
2025-03-24 14:22:10     at org.fao.geonet.services.main.GenericController.dispatch(GenericController.java:151)
2025-03-24 14:22:10     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2025-03-24 14:22:10     at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
2025-03-24 14:22:10     at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2025-03-24 14:22:10     at java.base/java.lang.reflect.Method.invoke(Method.java:566)
2025-03-24 14:22:10     at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
2025-03-24 14:22:10     at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
2025-03-24 14:22:10     at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
2025-03-24 14:22:10     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:903)
2025-03-24 14:22:10     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:809)
2025-03-24 14:22:10     at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
2025-03-24 14:22:10     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072)
2025-03-24 14:22:10     at jeeves.config.springutil.JeevesDispatcherServlet.access$001(JeevesDispatcherServlet.java:44)
2025-03-24 14:22:10     at jeeves.config.springutil.JeevesDispatcherServlet$1.doInTransaction(JeevesDispatcherServlet.java:56)
2025-03-24 14:22:10     at jeeves.config.springutil.JeevesDispatcherServlet$1.doInTransaction(JeevesDispatcherServlet.java:52)
2025-03-24 14:22:10     at jeeves.transaction.TransactionManager.runInTransaction(TransactionManager.java:75)
2025-03-24 14:22:10     at jeeves.config.springutil.JeevesDispatcherServlet.doDispatch(JeevesDispatcherServlet.java:49)
2025-03-24 14:22:10     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)
2025-03-24 14:22:10     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
2025-03-24 14:22:10     at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
2025-03-24 14:22:10     at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
2025-03-24 14:22:10     at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
2025-03-24 14:22:10     at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1459)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656)
2025-03-24 14:22:10     at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:292)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.fao.geonet.monitor.webapp.WebappMetricsFilter.doFilter(WebappMetricsFilter.java:121)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.fao.geonet.monitor.webapp.MetricsRegistryInitializerFilter.doFilter(MetricsRegistryInitializerFilter.java:58)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.fao.geonet.web.XFrameOptionsFilter.doFilter(XFrameOptionsFilter.java:110)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176)
2025-03-24 14:22:10     at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
2025-03-24 14:22:10     at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
2025-03-24 14:22:10     at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:394)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.fao.geonet.web.CORSResponseFilter.doFilter(CORSResponseFilter.java:133)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.geonetwork.http.SessionTimeoutCookieFilter.doFilter(SessionTimeoutCookieFilter.java:90)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.fao.geonet.web.GeoNetworkPortalFilter.doFilter(GeoNetworkPortalFilter.java:103)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:352)
2025-03-24 14:22:10     at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:117)
2025-03-24 14:22:10     at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126)
2025-03-24 14:22:10     at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131)
2025-03-24 14:22:10     at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter.doFilterInternal(BearerTokenAuthenticationFilter.java:149)
2025-03-24 14:22:10     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107)
2025-03-24 14:22:10     at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:227)
2025-03-24 14:22:10     at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:221)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:187)
2025-03-24 14:22:10     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:118)
2025-03-24 14:22:10     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:117)
2025-03-24 14:22:10     at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:361)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:225)
2025-03-24 14:22:10     at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:190)
2025-03-24 14:22:10     at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
2025-03-24 14:22:10     at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
2025-03-24 14:22:10     at jeeves.config.springutil.JeevesDelegatingFilterProxy.doFilter(JeevesDelegatingFilterProxy.java:74)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
2025-03-24 14:22:10     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:201)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1626)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:552)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
2025-03-24 14:22:10     at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
2025-03-24 14:22:10     at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
2025-03-24 14:22:10     at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505)
2025-03-24 14:22:10     at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:191)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
2025-03-24 14:22:10     at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
2025-03-24 14:22:10     at org.eclipse.jetty.server.Server.handle(Server.java:516)
2025-03-24 14:22:10     at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
2025-03-24 14:22:10     at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
2025-03-24 14:22:10     at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
2025-03-24 14:22:10     at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
2025-03-24 14:22:10     at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
2025-03-24 14:22:10     at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
2025-03-24 14:22:10     at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
2025-03-24 14:22:10     at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
2025-03-24 14:22:10     at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
2025-03-24 14:22:10     at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
2025-03-24 14:22:10     at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
2025-03-24 14:22:10     at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409)
2025-03-24 14:22:10     at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
2025-03-24 14:22:10     at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
2025-03-24 14:22:10     at java.base/java.lang.Thread.run(Thread.java:829)