fix(sso): let LastaFlute own the SAML SLO redirect - #3219
Merged
Conversation
marevol
force-pushed
the
saml-slo-response
branch
from
August 10, 2026 00:51
fa7f830 to
a8c23ea
Compare
marevol
force-pushed
the
saml-slo-response
branch
from
August 10, 2026 01:34
a8c23ea to
b581bf0
Compare
marevol
force-pushed
the
saml-slo-response
branch
from
August 10, 2026 01:57
b581bf0 to
ed49baf
Compare
getLogoutResponse() called the no-arg auth.processSLO(), which delegates to processSLO(false, null, false). With stay=false, java-saml answers an IdP-initiated LogoutRequest by calling response.sendRedirect() itself, which commits the servlet response. Fess then threw SsoMessageException, so SsoAction.logout() went on to saveInfo() and return a second redirect on the already committed response. processSLO(false, null, true) is now used so the URL is returned instead of being sent, and the method returns HtmlResponse.fromRedirectPathAsIs() for it. A LogoutResponse from the IdP still produces no URL and keeps reporting success through SsoMessageException. Also: - Guard against a missing IdP single logout service URL. Auth.getSLOResponseUrl() dereferences it without a null check, so a LogoutRequest arriving while SLO was unconfigured raised a NullPointerException whose null message was then shown to the user. logout(FessUserBean) already had this guard. - The unreachable "return null" at the end is gone; the method now returns the value of the mapped optional. - SP metadata is served as application/samlmetadata+xml with a .xml file name instead of application/xhtml+xml.
marevol
force-pushed
the
saml-slo-response
branch
from
August 10, 2026 02:12
ed49baf to
3d7274d
Compare
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.
1. The IdP-initiated logout response was written twice
getLogoutResponse()called the no-argauth.processSLO(), which delegates toprocessSLO(false, null, false). When the incoming message is aSAMLRequest(IdP-initiated logout), java-saml builds theLogoutResponseand, withstay=false, sends it itself:Fess then threw
SsoMessageException, andSsoAction#logoutcaught it, calledsaveInfo(...)and returnedredirect(LoginAction.class)— a second redirect on an already committed response.The call is now
processSLO(false, null, true), so the URL comes back to Fess and the method returnsHtmlResponse.fromRedirectPathAsIs(redirectUrl). LastaFlute stays in charge of the response. ASAMLResponsefrom the IdP produces no URL and still reports success throughSsoMessageException, exactly as before.2. NPE when SLO is not configured
Auth#getSLOResponseUrl()isand
getIdpSingleLogoutServiceResponseUrl()returnsnullwhen neither the response URL nor the SLO URL is set. ALogoutRequestarriving in that state raised aNullPointerException, which the catch-all wrapped into a user-facing message built frome.getMessage()— literally the stringnull.getLogoutResponse()now checks the URL up front and reports it, matching the guardlogout(FessUserBean)already had.3. Smaller items
return null;was unreachable, because the mapped lambda always threw. The method now returns the mapped optional's value.application/samlmetadata+xmlwith ametadata.xmlfile name rather thanapplication/xhtml+xml.Test
test_getLogoutResponse_withoutIdpSingleLogoutServiceUrlcovers the new guard. It is falsifiable: with the guard removed the request instead fails inside theAuthconstructor withInvalid settings: idp_entityId_not_found, ..., and the test catches that difference.Not covered here
SP-initiated SLO still calls
processSLOwithout a request ID, so theLogoutResponseis not bound to theLogoutRequestFess sent — the equivalent of what #3214 fixes for the login flow.LogoutActioninvalidates the session before the response comes back, so binding it needs a different place to keep the ID. Left for a follow-up.