Bug with SAML authentication

I may have hit a bug with SonarQube. Tried with 9.9.4 LTS, 9.9.5 LTA, and also upgraded the instance to 10.5.1 in hope that this had been fixed before me.

We use SonarQube Developer Edition, hosted on Windows from ZIP file, and I have recently configured SAML authentication with MS Entra ID there.

This is where the issue manifested.

We decorate our BitBucket pull requests with SonarQube, and the links that SonarQube provides in the pull request have the form of
https://sonarqube.domain.com/dashboard?id=project&pullRequest=PRID

The project is configured to be private, so when people click it, they are supposed to authenticate.

So if I try to open this link unauthenticated, SonarQube redirects me to
https://sonarqube.domain.com/sessions/new?return_to=%2Fdashboard%3Fid%3Dproject%26pullRequest%3DPRID&authorizationError=true)

Which is expected, of course, but then I click Log in with SAML there, authenticate successfully, and, suddenly, get
You’re not authorized to access this page. Please contact the administrator.

Well, I’m the administrator, and I have the following stack trace in web.log:

2024.05.29 16:14:33 WARN  web[aef5b0ff-b1c7-49ef-838c-4daa49dbe5f9][o.s.s.a.AuthenticationError] Fail to initialize authentication with provider 'saml'
java.nio.file.InvalidPathException: Illegal char <?> at index 10: /dashboard?id=**project**&pullRequest=**PRID**
	at java.base/sun.nio.fs.WindowsPathParser.normalize(WindowsPathParser.java:182)
	at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:153)
	at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
	at java.base/sun.nio.fs.WindowsPath.parse(WindowsPath.java:92)
	at java.base/sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:232)
	at java.base/java.nio.file.Path.of(Path.java:147)
	at org.sonar.server.authentication.OAuth2AuthenticationParametersImpl.escapePathTraversalChars(OAuth2AuthenticationParametersImpl.java:139)
	at org.sonar.server.authentication.OAuth2AuthenticationParametersImpl.sanitizeRedirectUrl(OAuth2AuthenticationParametersImpl.java:134)
	at org.sonar.server.authentication.OAuth2AuthenticationParametersImpl.init(OAuth2AuthenticationParametersImpl.java:63)
	at org.sonar.server.authentication.InitFilter.handleProvider(InitFilter.java:74)
	at org.sonar.server.authentication.InitFilter.doFilter(InitFilter.java:65)
	at org.sonar.server.platform.web.MasterServletFilter$JavaxFilterAdapter.doFilter(MasterServletFilter.java:227)
	at org.sonar.server.platform.web.MasterServletFilter$GodFilterChain.doFilter(MasterServletFilter.java:198)
	at org.sonar.server.platform.web.MasterServletFilter$HttpFilterChainAdapter.doFilter(MasterServletFilter.java:241)
	at org.sonar.server.authentication.DefaultAdminCredentialsVerifierFilter.doFilter(DefaultAdminCredentialsVerifierFilter.java:83)
	at org.sonar.server.platform.web.MasterServletFilter$JavaxFilterAdapter.doFilter(MasterServletFilter.java:227)
	at org.sonar.server.platform.web.MasterServletFilter$GodFilterChain.doFilter(MasterServletFilter.java:198)
	at org.sonar.server.platform.web.MasterServletFilter.doFilter(MasterServletFilter.java:146)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.sonar.server.platform.web.UserSessionFilter.doFilter(UserSessionFilter.java:83)
	at org.sonar.server.platform.web.UserSessionFilter.doFilter(UserSessionFilter.java:70)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.sonar.server.platform.web.CrossOriginFilter.doFilter(CrossOriginFilter.java:51)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.sonar.server.platform.web.CspFilter.doFilter(CspFilter.java:63)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.sonar.server.platform.web.CacheControlFilter.doFilter(CacheControlFilter.java:76)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.sonar.server.platform.web.SecurityServletFilter.doHttpFilter(SecurityServletFilter.java:60)
	at org.sonar.server.platform.web.SecurityServletFilter.doFilter(SecurityServletFilter.java:47)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.sonar.server.platform.web.RedirectFilter.doFilter(RedirectFilter.java:56)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.sonar.server.platform.web.EndpointPathFilter.doFilter(EndpointPathFilter.java:47)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.sonar.server.platform.web.RequestIdFilter.doFilter(RequestIdFilter.java:66)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.sonar.server.platform.web.RootFilter.doFilter(RootFilter.java:65)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:115)
	at jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.catalina.security.SecurityUtil.lambda$execute$0(SecurityUtil.java:222)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.Subject.doAsPrivileged(Subject.java:584)
	at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:250)
	at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:177)
	at org.apache.catalina.core.ApplicationFilterChain.lambda$doFilter$0(ApplicationFilterChain.java:138)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:137)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
	at ch.qos.logback.access.tomcat.LogbackValve.invoke(LogbackValve.java:267)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:346)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:928)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1786)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
	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(Thread.java:833)

I have a workaround for this situation - you just need to sign in to SonarQube at the main page, where URL does not have any question marks, and then you can re-click the link from the PR.

However, educating every developer experiencing this situation is not the outcome I’d want :slight_smile:

This is certainly true for any page that has a query part and I try to access with SAML auth.

Any suggestions, guys?

Hi Lexy,

Thank you very much for taking the time to report this bug. I confirm this is a non-expected behaviour, and I have created a ticket to fix it. I will let you know once the fix is released.

1 Like

Hello @Lexy_Zhitenev,

We have implemented a fix and it will be included in the SonarQube 10.6 release.
Thanks for reporting the issue!

2 Likes

Hey @dimitris.kavvathas,

I’ve just managed to install 10.6 and I don’t like the way the issue was fixed :frowning:

There is no exception after sign-in, but the deep link is lost.

Now if I’m unauthenticated and I click the PR link, I get to the authentication dialog, but after authentication I’m redirected to the main /projects page, and I have to close the tab and then click the link again to get to the PR page while my authentication cookie is still valid.

1 Like

@dimitris.kavvathas, @Colin, @nolwenn.cadic,

Sorry for pinging you all here, but the proper resolution of this issue is very important to me.

Could you please let me know if any further improvements are planned in this area?

Thank you!

Hi @Lexy_Zhitenev ,

Thanks for the extra-feedback.

I have created another ticket to fix this behavior.

Cheers,
Aurélien

1 Like