1

I am fairly new to webapps programming, so I thought of asking here.

I am implementing the SAML2 protocol in an open source app (namely OFBiz) but I am encountering a problem related to session loss after the protocol made its course.

I am following these steps to implement the protocol. Suppose ofbizwebsite.com is the URL of the site.

  1. Installed a custom plugin named SAMLIntegration which exposes the ACS page and the logic for login. To my understanding, a plugin (gradle) is like an indipendent java project, which translates to a new set of resources for the application (the plugin enables, for example, to visit ofbizwebsite.com/SAMLIntegration and setup some resources).
  2. Exposed the ACS page to ofbizwebsite.com/SAMLIntegration/control/acs, as well as metadata ofbizwebsite.com/SAMLIntegration/control/metadata.jsp
  3. Created the logic for login. Basically, an entity called UserLogin is saved in the session and recovered by a "checker" to understand if an user is logged in. Suppose that this checker is a HTTP WebEvent handler which can be called by any resource requiring authentication.

Now, the problem. If redirect the user to a resource on SAMLIntegration (for example ofbizwebsite.com/SAMLIntegration/control/aview or any ofbizwebsite.com/SAMLIntegration/control/* by calling response.sendRedirect("aview")) check works and login is preserved. Visiting any resource (for example ofbizwebsite.com/aplugin/control/anotherview) by navigating the application does not preserve the session.

OFBiz use internally a mechanism for preserving the userLogin between webapps, by creating an HashMap between and UUID and a UserLogin object. The UUID is passed between two different resources, appending this key to each path (so ofbizwebsite.com/aplugin/control/anotherview?externalKey=THEEFFECTIVEUUID)

To my understanding, changing from ofbizwebsite.com/SAMLIntegration/control/* to ofbizwebsite.com/aplugin/control/* determine a session loss. So, my idea was to replace the UUID mechanism with SAML2. However, I do not know how to solve this problem.

In particular, I would like to execute a SAML request each time the checker function is executed. If I can't find the user in the session, a SAML request is fired. However, my problem is HOW to manage the response. Normally, I would redirect it to the acs ofbizwebsite.com/SAMLIntegration/control/acs. Doing so, however, does not allow me to handle the response in the checker function, as the control is passed to another servlet by an external request (the SAML response fired by the IdP). Should I provide a different acs for each different path? (so one for SAMLIntegration and one for aplugin?) And, even if this was the case, how can I return the control to the checker function which has invoked the SAML request?

King Powa
  • 441
  • 3
  • 9
  • Hi, it's already some years now that I implemented SAML2 for a company in relation with OFBiz to handle SSO. I don't remember all details, but I did not create a plugin. I simply used HTTPD as a service provider to handle login requests (specifically handled in OFBiz with few changes) through the central identity provider of the company . So I guess you want to use a plugin to not change the OOTB OFBiz code that handles the (SSO) login? – JacquesLeRoux Jan 23 '23 at 17:21
  • Isn't OFBiz the SP in this case? Anyway, yes the reason behind a plugin was to mantain both the login methods. – King Powa Jan 25 '23 at 09:07
  • > Isn't OFBiz the SP in this case? Yes indeed rather, but IIRR I also used HTTPD for redirection. I'll ask if they have still the code... – JacquesLeRoux Jan 26 '23 at 13:09

1 Answers1

2

Here you go for installing the Shibboleth HTTPD module: https://pad.nereide.fr/SAMLWithShibboleth

You also need this method somewhere in OFBiz (I recommend LoginWorker.java, but you can put it where you want). It allows to use the externalAuthId of the userLogin for authentication, with the uid returned by the sso:

public static String checkShibbolethRequestRemoteUserLogin(HttpServletRequest request, HttpServletResponse response) {
    LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
    Delegator delegator = dispatcher.getDelegator();
    
    // make sure the user isn't already logged in
    if (!LoginWorker.isUserLoggedIn(request)) {
        String remoteUserId = (String) request.getAttribute("uid"); // This is the one which works, uid at Idp, remoteUserId here
        if (UtilValidate.isNotEmpty(remoteUserId)) {
            //we resolve if the user exist with externalAuthId
            String userLoginId = null;
            GenericValue userLogin;
            try {
                List<GenericValue> userLogins = delegator.findList("UserLogin",
                                EntityCondition.makeConditionMap("externalAuthId", remoteUserId, "enabled", "Y"),
                                null, null, null, true);
                userLogin = userLogins.size() == 1 ? userLogins.get(0) : null;
            } catch (GenericEntityException e) {
                Debug.logError(e, module);
                return "error";
            }
            if (userLogin != null) {
                userLoginId = userLogin.getString("userLoginId");
            }
            //now try to log the user found
            return LoginWorker.loginUserWithUserLoginId(request, response, userLoginId);
        }
    }
    return "success";
}

You also need to have this method as an OFBiz preprocessor in the webapp controllers. I suggest to have a look at common-controller.xml.

Finally you need the configs that redirect to the SSO page if no session. That should do the job, at least it works for them...

Finally I recommend https://www.varonis.com/blog/what-is-saml in case of need.

Florian Motteau
  • 3,467
  • 1
  • 22
  • 42
JacquesLeRoux
  • 577
  • 4
  • 10