fix(sso): use query response mode so the Entra ID callback keeps its session - #3215
Merged
Conversation
…session getAuthUrl() asked Entra ID for response_mode=form_post, so the authorization response came back as a cross-site POST. Fess sets SameSite=Lax on the session cookie (tomcat.sameSiteCookies, applied in FessBoot), and a Lax cookie is not sent on a cross-site POST. Because the attribute is set explicitly, Chrome's two-minute "Lax + POST" grace period does not apply either -- that grace period only covers cookies with no SameSite attribute at all. getSession(false) therefore returned null on the callback, the stored state was unreachable, and getLoginCredential() fell through to redirecting back to the authorization endpoint, looping forever. The default value of tomcat.sameSiteCookies was only introduced recently; before that the attribute was unset and the grace period kept form_post working. Ask for response_mode=query instead. With response_type=code the response is then a top-level GET navigation, which does carry a Lax cookie, and query is the default response mode for the authorization code flow. containsAuthenticationData() accepts GET as well as POST, so a deployment that already set tomcat.sameSiteCookies=none and relies on form_post keeps working. Also stop bouncing a callback that arrived without a session back to the authorization endpoint. That is what turned a missing cookie into an infinite redirect; it now logs a warning and falls through to the login page.
Covers the loop-prevention added in the previous commit: without it, getLoginCredential() returns an ActionResponseCredential that redirects back to the authorization endpoint, and the callback arrives without a session again.
marevol
force-pushed
the
entraid-response-mode-query
branch
from
August 10, 2026 01:06
de48505 to
22f3532
Compare
marevol
added a commit
that referenced
this pull request
Aug 10, 2026
java-saml exposes Saml2Settings#getSecurityWarnings(), which flags weak but non-fatal configuration. Nothing called it, so a deployment running on the permissive defaults had no way to learn about it except by reading the code. getSettings() now logs the warnings at WARN. Since the settings are rebuilt on every request, the warnings are repeated only when they change, so editing the configuration from the admin UI re-reports the new state without flooding the log in between. With the shipped defaults the message is: Insecure SAML settings: deprecated_signature_algorithms_not_rejected, assertions_and_messages_not_required_signed. See the SAML SSO documentation for the recommended values. The tomcat_config.properties note this change originally carried about SameSite and the SAML HTTP-POST binding is dropped: #3215 landed the same guidance on master, covering both SAML and Entra ID form_post.
marevol
added a commit
that referenced
this pull request
Aug 10, 2026
java-saml exposes Saml2Settings#getSecurityWarnings(), which flags weak but non-fatal configuration. Nothing called it, so a deployment running on the permissive defaults had no way to learn about it except by reading the code. getSettings() now logs the warnings at WARN. Since the settings are rebuilt on every request, the warnings are repeated only when they change, so editing the configuration from the admin UI re-reports the new state without flooding the log in between. With the shipped defaults the message is: Insecure SAML settings: deprecated_signature_algorithms_not_rejected, assertions_and_messages_not_required_signed. See the SAML SSO documentation for the recommended values. The tomcat_config.properties note this change originally carried about SameSite and the SAML HTTP-POST binding is dropped: #3215 landed the same guidance on master, covering both SAML and Entra ID form_post.
marevol
added a commit
that referenced
this pull request
Aug 10, 2026
java-saml exposes Saml2Settings#getSecurityWarnings(), which flags weak but non-fatal configuration. Nothing called it, so a deployment running on the permissive defaults had no way to learn about it except by reading the code. getSettings() now logs the warnings at WARN. Since the settings are rebuilt on every request, the warnings are repeated only when they change, so editing the configuration from the admin UI re-reports the new state without flooding the log in between. With the shipped defaults the message is: Insecure SAML settings: deprecated_signature_algorithms_not_rejected, assertions_and_messages_not_required_signed. See the SAML SSO documentation for the recommended values. The tomcat_config.properties note this change originally carried about SameSite and the SAML HTTP-POST binding is dropped: #3215 landed the same guidance on master, covering both SAML and Entra ID form_post.
marevol
added a commit
that referenced
this pull request
Aug 10, 2026
java-saml exposes Saml2Settings#getSecurityWarnings(), which flags weak but non-fatal configuration. Nothing called it, so a deployment running on the permissive defaults had no way to learn about it except by reading the code. getSettings() now logs the warnings at WARN. Since the settings are rebuilt on every request, the warnings are repeated only when they change, so editing the configuration from the admin UI re-reports the new state without flooding the log in between. With the shipped defaults the message is: Insecure SAML settings: deprecated_signature_algorithms_not_rejected, assertions_and_messages_not_required_signed. See the SAML SSO documentation for the recommended values. The tomcat_config.properties note this change originally carried about SameSite and the SAML HTTP-POST binding is dropped: #3215 landed the same guidance on master, covering both SAML and Entra ID form_post.
marevol
added a commit
that referenced
this pull request
Aug 10, 2026
java-saml exposes Saml2Settings#getSecurityWarnings(), which flags weak but non-fatal configuration. Nothing called it, so a deployment running on the permissive defaults had no way to learn about it except by reading the code. getSettings() now logs the warnings at WARN. Since the settings are rebuilt on every request, the warnings are repeated only when they change, so editing the configuration from the admin UI re-reports the new state without flooding the log in between. With the shipped defaults the message is: Insecure SAML settings: deprecated_signature_algorithms_not_rejected, assertions_and_messages_not_required_signed. See the SAML SSO documentation for the recommended values. The tomcat_config.properties note this change originally carried about SameSite and the SAML HTTP-POST binding is dropped: #3215 landed the same guidance on master, covering both SAML and Entra ID form_post.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
getAuthUrl()asked Entra ID forresponse_mode=form_post:+ "/oauth2/v2.0/authorize?response_type=code&scope=...&response_mode=form_post&redirect_uri="so the authorization response comes back as a cross-site POST from
login.microsoftonline.com.Fess sets
SameSite=Laxon the session cookie —tomcat.sameSiteCookies = laxintomcat_config.properties, applied to the TomcatCookieProcessorinFessBoot. ALaxcookie is not sent on a cross-site POST. And because the attribute is set explicitly,
Chrome's two-minute "Lax + POST" grace period does not apply either — that grace period only
covers cookies with no
SameSiteattribute at all.So on the callback:
request.getSession(false)returnsnullstate/nonceare unreachable, so the response can never be validatedgetLoginCredential()falls through toActionResponseCredential→ redirect to theauthorization endpoint → the loop repeats forever
The default value of
tomcat.sameSiteCookieswas only added recently (#3136). Before that theattribute was unset, so the grace period kept
form_postworking — this is a regression ratherthan a long-standing bug.
Fix
Ask for
response_mode=query. Withresponse_type=codethe response is then a top-levelGET navigation, which does carry a
Laxcookie.queryis also the default response mode forthe authorization code flow, so nothing about the app registration changes —
response_modeischosen by us in the authorization request, not configured on the Entra ID side.
containsAuthenticationData()now acceptsGETas well asPOST, so a deployment that alreadyset
tomcat.sameSiteCookies=noneand relies onform_postkeeps working.Stop bouncing a session-less callback back to the IdP. That is what turned a missing cookie
into an infinite redirect. It now logs a warning naming the likely cause and returns
null, soSsoActionshows the SSO login error and goes to the login page once.The comment on
tomcat.sameSiteCookiessaid "Lax keeps OAuth/OIDC redirects working", which istrue for redirect-based callbacks but not for POST ones. Reworded to say which setups need
none— SAML's HTTP-POST binding has the same constraint.On putting the code in the query string
The authorization code is single-use, short-lived, and cannot be redeemed without the client
secret, which is why
queryis the standard mode for a confidential client. #3213 stops the codebeing written to the debug log.
Tests
EntraIdAuthenticator's unit test class, 6 new tests:test_getAuthUrl_requestsQueryResponseMode/...OnV1Endpoint— assertsresponse_mode=query,no
form_post, and thatresponse_type,stateandnonceare unchangedtest_containsAuthenticationData_acceptsQueryModeCallback— GET withcodetest_containsAuthenticationData_acceptsFormPostCallback— POST still acceptedtest_containsAuthenticationData_acceptsErrorCallback— GET witherrortest_containsAuthenticationData_ignoresRequestWithoutArtifacts— a plain visit to/ssostillstarts a fresh login
All 4 behavioural ones failed before the change.
(the whole
org.codelibs.fess.ssopackage, including the OIDC and SAML authenticator tests)