OFBiz中SAML2重定向后跨WebApp会话丢失问题求助
Hey there, let's work through your SAML2 cross-webapp session issue in OFBiz step by step. I’ve dealt with similar multi-module session problems in OFBiz before, so here’s how to approach this:
Recap of Your Problem
You’ve implemented SAML2 via a custom SAMLIntegration plugin in OFBiz:
- The plugin hosts your ACS (
ofbizwebsite.com/SAMLIntegration/control/acs) and metadata endpoints - Your
checkerWebEvent handler validates user sessions - Sessions work fine within the
SAMLIntegrationplugin, but are lost when navigating to other OFBiz webapps (likeofbizwebsite.com/aplugin/control/anotherview) - You want to replace OFBiz’s built-in
externalKeyUUID mechanism with SAML2, but you’re stuck on how to trigger a SAML request from thecheckerhandler and return control to the original requested resource after authentication.
Core Issue to Solve
SAML2’s SP-initiated flow works by redirecting the user to the IdP, then back to your ACS. The problem is that this redirect breaks the context of the original request (the aplugin resource the user was trying to access). You need to:
- Save the original request context before redirecting to the IdP
- Restore that context after the ACS processes the IdP’s response
- Ensure user session data is accessible across all OFBiz webapps
Step-by-Step Solutions
1. Persist Original Request Context Before SAML Redirect
When your checker handler detects no valid user session:
- Capture the full URL of the original request (including query parameters)
- Store this URL in a global, cross-webapp cache (OFBiz’s
SimpleCacheis perfect for this— it’s designed for shared state across modules) - Generate a unique temporary ID to associate with the stored URL
- Pass this temporary ID as the
RelayStateparameter in your SAML AuthnRequest (SAML standard guarantees the IdP will send this value back to your ACS unmodified)
2. Unify ACS Handling & Redirect Back to Original Resource
You don’t need separate ACS endpoints for each webapp— keep using your existing SAMLIntegration/control/acs. Here’s what to do in the ACS handler:
- Validate the SAML response from the IdP and retrieve the user’s identity (e.g., NameID)
- Create or fetch the corresponding
UserLoginentity in OFBiz - Store the
UserLoginin a cross-webapp cache (again,SimpleCacheworks) and associate it with the user’s SAML NameID - Set a domain-wide cookie (with
domain=ofbizwebsite.comandpath=/) containing the SAML NameID— this lets all webapps access the user’s identity - Retrieve the temporary ID from the
RelayStateparameter, fetch the original request URL from the cache, and redirect the user back to that URL
3. Update the checker Handler to Use Cross-Webapp Session Data
Modify your checker handler to:
- First check the current webapp’s session for a
UserLogin - If none exists, check the domain-wide SAML cookie for the NameID
- Use the NameID to fetch the
UserLoginfrom the cross-webapp cache - If found, populate the current webapp’s session with the
UserLoginto avoid re-authenticating for subsequent requests in that webapp
Example Code Snippets
Checker Handler Logic
public class CheckerEventHandler implements EventHandler { public String invoke(EventExecutionContext eec) throws EventHandlerException { HttpServletRequest request = eec.getRequest(); HttpServletResponse response = eec.getResponse(); // Check current webapp session first UserLogin userLogin = (UserLogin) request.getSession().getAttribute("userLogin"); if (userLogin == null) { // Check for SAML NameID cookie String samlNameId = null; Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if ("samlNameId".equals(cookie.getName())) { samlNameId = cookie.getValue(); break; } } } // Try to fetch UserLogin from cross-webapp cache if (samlNameId != null) { userLogin = (UserLogin) SimpleCache.getCache("SAMLUserSessionCache").get(samlNameId); if (userLogin != null) { request.getSession().setAttribute("userLogin", userLogin); return "success"; } } // No valid session— initiate SAML auth flow String originalUrl = request.getRequestURI(); if (request.getQueryString() != null) { originalUrl += "?" + request.getQueryString(); } String tempRelayId = UUID.randomUUID().toString(); // Store original URL in cache (1-hour expiration) SimpleCache.getCache("SAMLRelayStateCache").put(tempRelayId, originalUrl, 3600); // Build SAML AuthnRequest with RelayState Saml2AuthRequest authRequest = SamlService.getInstance().generateAuthnRequest(); authRequest.setRelayState(tempRelayId); String idpRedirectUrl = SamlService.getInstance().buildIdpRedirectUrl(authRequest); response.sendRedirect(idpRedirectUrl); return null; // Halt current request to trigger redirect } return "success"; } }
ACS Handler Logic
public class AcsEventHandler implements EventHandler { public String invoke(EventExecutionContext eec) throws EventHandlerException { HttpServletRequest request = eec.getRequest(); HttpServletResponse response = eec.getResponse(); // Process and validate SAML response Saml2AuthResponse authResponse = SamlService.getInstance().processAcsRequest(request); String samlNameId = authResponse.getNameId(); // Create or retrieve UserLogin from OFBiz UserLogin userLogin = UserLoginService.getInstance().getOrCreateUser(samlNameId, authResponse.getAttributes()); // Store UserLogin in cross-webapp cache SimpleCache.getCache("SAMLUserSessionCache").put(samlNameId, userLogin); // Set domain-wide cookie for SAML identity Cookie samlCookie = new Cookie("samlNameId", samlNameId); samlCookie.setDomain("ofbizwebsite.com"); samlCookie.setPath("/"); samlCookie.setHttpOnly(true); samlCookie.setSecure(true); // Enable if using HTTPS response.addCookie(samlCookie); // Redirect back to original request String tempRelayId = request.getParameter("RelayState"); String originalUrl = (String) SimpleCache.getCache("SAMLRelayStateCache").get(tempRelayId); if (originalUrl == null) { originalUrl = "/"; // Fallback to homepage if context is lost } response.sendRedirect(originalUrl); return null; } }
Key Takeaways
- No need for multiple ACS endpoints: Your single
SAMLIntegrationACS can handle all webapps by usingRelayStateto track original requests - Cross-webapp session sharing: Use OFBiz’s
SimpleCachefor shared user state and domain-wide cookies to identify users across webapps - Preserve request context: Always store the original URL before redirecting to the IdP— this ensures users land where they intended after authentication
内容的提问来源于stack exchange,提问作者King Powa

