我对webapps编程相当陌生,所以我想在这里问一下。
我正在一个开源应用程序(即OFBiz)中实现SAML2协议,但在协议完成后,我遇到了与会话丢失相关的问题。
我遵循这些步骤来实现协议。设ofbizwebsite.com
为站点的URL。
- 安装了一个名为
SAMLIntegration
的自定义插件,该插件暴露了ACS页面和登录逻辑。在我看来,一个插件(gradle)就像一个独立的java项目,它为应用程序转换了一组新的资源(例如,插件允许访问ofbizwebsite.com/SAMLIntegration
并设置一些资源)。 - 将ACS页面暴露给
ofbizwebsite.com/SAMLIntegration/control/acs
,以及元数据ofbizwebsite.com/SAMLIntegration/control/metadata.jsp
- 创建登录逻辑。基本上,一个名为
UserLogin
的实体被保存在会话中,并由"检查器"恢复。了解用户是否已登录。假设这个检查器是一个HTTP WebEvent处理程序,可以被任何需要身份验证的资源调用。
问题来了。如果将用户重定向到SAMLIntegration
上的资源(例如,通过调用response.sendRedirect("aview")
将用户重定向到ofbizwebsite.com/SAMLIntegration/control/aview
或任何ofbizwebsite.com/SAMLIntegration/control/*
),则check工作并保留登录。通过导航应用程序访问任何资源(例如ofbizwebsite.com/aplugin/control/anotherview
)都不会保留会话。
OFBiz在内部使用一种机制来保存webapps之间的userLogin,通过在UUID和UserLogin
对象之间创建一个HashMap。UUID在两个不同的资源之间传递,将此键附加到每个路径(例如ofbizwebsite.com/aplugin/control/anotherview?externalKey=THEEFFECTIVEUUID
)
根据我的理解,从ofbizwebsite.com/SAMLIntegration/control/*
更改为ofbizwebsite.com/aplugin/control/*
确定会话丢失。因此,我的想法是用SAML2取代UUID机制。然而,我不知道如何解决这个问题。
ofbizwebsite.com/SAMLIntegration/control/acs
。但是,这样做不允许我在检查器函数中处理响应,因为控件通过外部请求(由IdP触发的SAML响应)传递给另一个servlet。我应该为每个不同的路径提供不同的acs吗?(一个用于SAMLIntegration
,一个用于aplugin
?)而且,即使是这种情况,我如何将控件返回给调用了SAML请求的检查器函数?安装Shibboleth HTTPD模块:https://pad.nereide.fr/SAMLWithShibboleth
你也需要这个方法在OFBiz的某处(我推荐LoginWorker.java,但你可以把它放在你想要的地方)。它允许使用userLogin的externalAuthId进行身份验证,并使用sso:
返回的uidpublic 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";
}
你还需要在webapp控制器中将这个方法作为OFBiz预处理器。我建议看一下common-controller.xml。
最后,如果没有会话,您需要重定向到SSO页面的配置。这应该能起作用,至少对他们有用。
最后我推荐https://www.varonis.com/blog/what-is-saml,如果需要的话。