Error in base64 decoding saml message in Keycloak

We’re trying setup Keycloak (version 20.0.1) with an EHerkenning/EIDAS (Dutch/European identity system for businesses) Identity provider using SAML.
We can connect with the EHerkenning/EIDAS broker (their login page is shown). The response posted to the Keycloak endpoint however causes an exception. Keycloak displays “Invalid response from identity provider.”

In the Keycloak logs we found the following error;

2022-11-09 14:01:30,735 ERROR [org.keycloak.saml.common] (executor-thread-0) Error in base64 decoding saml message.: java.lang.RuntimeException: PL00062: Parser : Unknown tag:EncryptedAttribute::location=Line number = 159

Column number = 252

System Id = null

Public Id = null

Location Uri= null

CharacterOffset = 35248


at org.keycloak.saml.common.DefaultPicketLinkLogger.parserUnknownTag(DefaultPicketLinkLogger.java:359)

at org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAttributeStatementParser.processSubElement(SAMLAttributeStatementParser.java:56)

at org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAttributeStatementParser.processSubElement(SAMLAttributeStatementParser.java:31)

at org.keycloak.saml.common.parsers.AbstractStaxParser.parse(AbstractStaxParser.java:97)

at org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAssertionParser.processSubElement(SAMLAssertionParser.java:96)

at org.keycloak.saml.processing.core.parsers.saml.assertion.SAMLAssertionParser.processSubElement(SAMLAssertionParser.java:34)

at org.keycloak.saml.common.parsers.AbstractStaxParser.parse(AbstractStaxParser.java:97)

at org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLResponseParser.processSubElement(SAMLResponseParser.java:77)

at org.keycloak.saml.processing.core.parsers.saml.protocol.SAMLResponseParser.processSubElement(SAMLResponseParser.java:38)

at org.keycloak.saml.common.parsers.AbstractStaxParser.parse(AbstractStaxParser.java:97)

at org.keycloak.saml.processing.core.parsers.saml.SAMLParser.parse(SAMLParser.java:123)

at org.keycloak.saml.common.parsers.AbstractParser.parse(AbstractParser.java:98)

at org.keycloak.saml.common.parsers.AbstractParser.parse(AbstractParser.java:102)

at org.keycloak.saml.processing.api.saml.v2.response.SAML2Response.getSAML2ObjectFromStream(SAML2Response.java:389)

at org.keycloak.saml.SAMLRequestParser.parseResponseDocument(SAMLRequestParser.java:104)

at org.keycloak.broker.saml.SAMLEndpoint$PostBinding.extractResponseDocument(SAMLEndpoint.java:726)

at org.keycloak.broker.saml.SAMLEndpoint$Binding.handleSamlResponse(SAMLEndpoint.java:624)

at org.keycloak.broker.saml.SAMLEndpoint$Binding.execute(SAMLEndpoint.java:276)

at org.keycloak.broker.saml.SAMLEndpoint.postBinding(SAMLEndpoint.java:187)

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 org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)

at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)

at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)

at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)

at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)

at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)

at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)

at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)

at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)

at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152)

at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183)

at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)

at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)

at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)

at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)

at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)

at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)

at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)

at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)

at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)

at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)

at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)

at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)

at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)

at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:173)

at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:140)

at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:84)

at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:71)

at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)

at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:173)

at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:140)

at io.quarkus.vertx.http.runtime.VertxHttpRecorder$6.handle(VertxHttpRecorder.java:430)

at io.quarkus.vertx.http.runtime.VertxHttpRecorder$6.handle(VertxHttpRecorder.java:408)

at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)

at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:173)

at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:140)

at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$0(QuarkusRequestFilter.java:82)

at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:564)

at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)

at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)

at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)

at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)

at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)

at java.base/java.lang.Thread.run(Thread.java:829)

We’re running out of ideas what causes this issue. It’s also hard to debug, because of the lack of details in the logging of Keycloak, even with verbose logging enabled.

Does anyone have any clue what is going wrong with the base64 decoding of the SAML response?

  • We’ve tried to decode the response using saml tool, however SAML tool is also unable to decode the message.
  • We’ve tried removing the newlines from the entire SAML response (both in the encrypted, base64 hashed attributes and the response as a whole). Every change made results in Keycloak not accepting the new base64 encoded SAML response or crashes Keycloak without any logging at all.