Users should be able to successfully authenticate using SAML and access the application.
Actual
Users encounter a generic error message ("Error. Sorry, something went wrong.") with a status code of 500 and are unable to login.
Steps to reproduce
Update to the latest version
Access the Structurizr On-Premises application.
Attempt to login using your SAML credentials.
Observe the error message and status code.
Version/build information
v2024-11-04
Severity
Critical
Priority
I have no budget and there's no rush, please fix this for free
More information
The login functionality has stopped working after upgrading to the latest versions of Structurizr On-Premises. We use SAML for authentication with Keycloak as the Identity Provider (IdP). Upon attempting to login, users encounter an "Error. Sorry, something went wrong." message with a status code of 500.
The application functioned correctly with SAML login prior to the upgrade.
The stack trace from the server log (/usr/local/tomcat/logs/localhost.2024-11-04.log) indicates an IncompatibleClassChangeError:
java.lang.IncompatibleClassChangeError: Class com.google.common.base.Predicates$ObjectPredicate$1 does not implement the requested interface java.util.function.Predicate
Could it be related to the pinned version of guava? 🤔
The content of /usr/local/tomcat/logs/localhost.2024-11-04.log:
04-Nov-2024 23:07:56.286 INFO [main] org.apache.catalina.core.ApplicationContext.log No Spring WebApplicationInitializer types detected on classpath
04-Nov-2024 23:07:56.611 INFO [main] org.apache.catalina.core.ApplicationContext.log Initializing Spring root WebApplicationContext
04-Nov-2024 23:07:59.562 INFO [main] org.apache.catalina.core.ApplicationContext.log Initializing Spring DispatcherServlet 'root'
04-Nov-2024 23:09:27.855 SEVERE [http-nio-8080-exec-6] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [root] in context with path [] threw exception [Filter execution threw an exception] with root cause
java.lang.IncompatibleClassChangeError: Class com.google.common.base.Predicates$ObjectPredicate$1 does not implement the requested interface java.util.function.Predicate
at net.shibboleth.utilities.java.support.logic.PredicateSupport.lambda$and$0(PredicateSupport.java:171)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(Unknown Source)
at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source)
at org.opensaml.xmlsec.impl.BasicSignatureSigningParametersResolver.getEffectiveSignatureAlgorithms(BasicSignatureSigningParametersResolver.java:315)
at org.opensaml.xmlsec.impl.BasicSignatureSigningParametersResolver.resolveAndPopulateCredentialAndSignatureAlgorithm(BasicSignatureSigningParametersResolver.java:235)
at org.opensaml.saml.security.impl.SAMLMetadataSignatureSigningParametersResolver.resolveAndPopulateCredentialAndSignatureAlgorithm(SAMLMetadataSignatureSigningParametersResolver.java:70)
at org.opensaml.xmlsec.impl.BasicSignatureSigningParametersResolver.resolveSingle(BasicSignatureSigningParametersResolver.java:119)
at org.opensaml.xmlsec.impl.BasicSignatureSigningParametersResolver.resolveSingle(BasicSignatureSigningParametersResolver.java:59)
at org.springframework.security.saml2.provider.service.web.authentication.OpenSamlSigningUtils.resolveSigningParameters(OpenSamlSigningUtils.java:111)
at org.springframework.security.saml2.provider.service.web.authentication.OpenSamlSigningUtils.sign(OpenSamlSigningUtils.java:81)
at org.springframework.security.saml2.provider.service.web.authentication.OpenSamlAuthenticationRequestResolver.resolve(OpenSamlAuthenticationRequestResolver.java:159)
at org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver.resolve(OpenSaml4AuthenticationRequestResolver.java:73)
at org.springframework.security.saml2.provider.service.web.Saml2WebSsoAuthenticationRequestFilter.doFilterInternal(Saml2WebSsoAuthenticationRequestFilter.java:98)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter.doFilterInternal(Saml2LogoutResponseFilter.java:112)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter.doFilterInternal(Saml2LogoutRequestFilter.java:126)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:362)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:278)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at com.structurizr.onpremises.web.NoOpSpringSessionRepositoryFilter.doFilter(NoOpSpringSessionRepositoryFilter.java:15)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:362)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:278)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:101)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:663)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:384)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Unknown Source)
The content of /usr/local/structurizr/logs/structurizr.log:
[DEBUG] 2024-11-04 23:33:52.491 [http-nio-8080-exec-5] FilterChainProxy - Securing GET /dashboard
[DEBUG] 2024-11-04 23:33:52.491 [http-nio-8080-exec-5] FilterChainProxy - Secured GET /dashboard
[DEBUG] 2024-11-04 23:33:52.492 [http-nio-8080-exec-5] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.493 [http-nio-8080-exec-5] MethodSecurityInterceptor - Failed to authorize ReflectiveMethodInvocation: public java.lang.String com.structurizr.onpremises.web.home.HomePageController.showAuthenticatedDashboard(java.lang.String,int,int,org.springframework.ui.ModelMap); target is of class [com.structurizr.onpremises.web.home.HomePageController] with attributes [[authorize: 'isAuthenticated()', filter: 'null', filterTarget: 'null']]
[DEBUG] 2024-11-04 23:33:52.495 [http-nio-8080-exec-5] HttpSessionRequestCache - Saved request http://localhost:8080/dashboard?continue to session
[DEBUG] 2024-11-04 23:33:52.495 [http-nio-8080-exec-5] DelegatingAuthenticationEntryPoint - Trying to match using And [Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], Not [And [Or [Ant [pattern='/login'], Ant [pattern='/favicon.ico']], And [Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.HeaderContentNegotiationStrategy@78df0b6d, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]]]]
[DEBUG] 2024-11-04 23:33:52.496 [http-nio-8080-exec-5] DelegatingAuthenticationEntryPoint - Match found! Executing org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint@e9b77ef
[DEBUG] 2024-11-04 23:33:52.496 [http-nio-8080-exec-5] DefaultRedirectStrategy - Redirecting to http://localhost:8080/saml2/authenticate/structurizr
[DEBUG] 2024-11-04 23:33:52.507 [http-nio-8080-exec-7] FilterChainProxy - Securing GET /saml2/authenticate/structurizr
[DEBUG] 2024-11-04 23:33:52.534 [http-nio-8080-exec-1] FilterChainProxy - Securing GET /static/css/bootstrap-3.3.7.min.css
[DEBUG] 2024-11-04 23:33:52.535 [http-nio-8080-exec-1] FilterChainProxy - Secured GET /static/css/bootstrap-3.3.7.min.css
[DEBUG] 2024-11-04 23:33:52.537 [http-nio-8080-exec-1] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.542 [http-nio-8080-exec-9] FilterChainProxy - Securing GET /static/js/structurizr-2024.11.04.js
[DEBUG] 2024-11-04 23:33:52.543 [http-nio-8080-exec-2] FilterChainProxy - Securing GET /static/css/structurizr.css
[DEBUG] 2024-11-04 23:33:52.543 [http-nio-8080-exec-4] FilterChainProxy - Securing GET /static/js/structurizr-ui-2024.11.04.js
[DEBUG] 2024-11-04 23:33:52.543 [http-nio-8080-exec-8] FilterChainProxy - Securing GET /static/js/jquery-3.6.3.min.js
[DEBUG] 2024-11-04 23:33:52.543 [http-nio-8080-exec-4] FilterChainProxy - Secured GET /static/js/structurizr-ui-2024.11.04.js
[DEBUG] 2024-11-04 23:33:52.543 [http-nio-8080-exec-8] FilterChainProxy - Secured GET /static/js/jquery-3.6.3.min.js
[DEBUG] 2024-11-04 23:33:52.542 [http-nio-8080-exec-10] FilterChainProxy - Securing GET /static/css/bootstrap-theme-3.3.7.min.css
[DEBUG] 2024-11-04 23:33:52.543 [http-nio-8080-exec-10] FilterChainProxy - Secured GET /static/css/bootstrap-theme-3.3.7.min.css
[DEBUG] 2024-11-04 23:33:52.544 [http-nio-8080-exec-10] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.542 [http-nio-8080-exec-6] FilterChainProxy - Securing GET /static/js/bootstrap-3.3.7.min.js
[DEBUG] 2024-11-04 23:33:52.543 [http-nio-8080-exec-9] FilterChainProxy - Secured GET /static/js/structurizr-2024.11.04.js
[DEBUG] 2024-11-04 23:33:52.545 [http-nio-8080-exec-6] FilterChainProxy - Secured GET /static/js/bootstrap-3.3.7.min.js
[DEBUG] 2024-11-04 23:33:52.546 [http-nio-8080-exec-9] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.546 [http-nio-8080-exec-6] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.550 [http-nio-8080-exec-8] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.543 [http-nio-8080-exec-2] FilterChainProxy - Secured GET /static/css/structurizr.css
[DEBUG] 2024-11-04 23:33:52.551 [http-nio-8080-exec-4] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.552 [http-nio-8080-exec-2] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.560 [http-nio-8080-exec-5] FilterChainProxy - Securing GET /static/img/structurizr-banner.png
[DEBUG] 2024-11-04 23:33:52.558 [http-nio-8080-exec-3] FilterChainProxy - Securing GET /static/js/structurizr-util-2024.11.04.js
[DEBUG] 2024-11-04 23:33:52.560 [http-nio-8080-exec-5] FilterChainProxy - Secured GET /static/img/structurizr-banner.png
[DEBUG] 2024-11-04 23:33:52.560 [http-nio-8080-exec-3] FilterChainProxy - Secured GET /static/js/structurizr-util-2024.11.04.js
[DEBUG] 2024-11-04 23:33:52.563 [http-nio-8080-exec-3] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.564 [http-nio-8080-exec-7] FilterChainProxy - Securing GET /static/img/structurizr-banner-dark.png
[DEBUG] 2024-11-04 23:33:52.564 [http-nio-8080-exec-7] FilterChainProxy - Secured GET /static/img/structurizr-banner-dark.png
[DEBUG] 2024-11-04 23:33:52.565 [http-nio-8080-exec-7] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.565 [http-nio-8080-exec-5] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.591 [http-nio-8080-exec-1] FilterChainProxy - Securing GET /static/bootstrap-icons/box-arrow-in-right.svg
[DEBUG] 2024-11-04 23:33:52.593 [http-nio-8080-exec-1] FilterChainProxy - Secured GET /static/bootstrap-icons/box-arrow-in-right.svg
[DEBUG] 2024-11-04 23:33:52.596 [http-nio-8080-exec-1] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
[DEBUG] 2024-11-04 23:33:52.601 [http-nio-8080-exec-6] FilterChainProxy - Securing GET /static/css/structurizr-print.css
[DEBUG] 2024-11-04 23:33:52.601 [http-nio-8080-exec-6] FilterChainProxy - Secured GET /static/css/structurizr-print.css
[DEBUG] 2024-11-04 23:33:52.602 [http-nio-8080-exec-6] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
Expected
Users should be able to successfully authenticate using SAML and access the application.
Actual
Users encounter a generic error message ("Error. Sorry, something went wrong.") with a status code of 500 and are unable to login.
Steps to reproduce
Version/build information
v2024-11-04
Severity
Critical
Priority
I have no budget and there's no rush, please fix this for free
More information
The login functionality has stopped working after upgrading to the latest versions of Structurizr On-Premises. We use SAML for authentication with Keycloak as the Identity Provider (IdP). Upon attempting to login, users encounter an "Error. Sorry, something went wrong." message with a status code of 500.
The application functioned correctly with SAML login prior to the upgrade. The stack trace from the server log (/usr/local/tomcat/logs/localhost.2024-11-04.log) indicates an IncompatibleClassChangeError:
java.lang.IncompatibleClassChangeError: Class com.google.common.base.Predicates$ObjectPredicate$1 does not implement the requested interface java.util.function.Predicate
The content of /usr/local/tomcat/logs/localhost.2024-11-04.log:
The content of /usr/local/structurizr/logs/structurizr.log: