TransactionalStateSupport 不保存变量

TransactionalStateSupport doesn't save variables

背景信息:

我目前正在实现一个自定义 Idp 适配器,它基本上包装了 ReferenceID 适配器并添加了额外的功能。 我正在使用 TransactionalStateSupport 使 oauth-client-id(在第一个 HTTP 请求期间作为查询参数可用)在整个事务中都可以访问。 不幸的是,这对我来说不是很好。

值似乎没有存储:

String resumePath = (String)inParameters.get("com.pingidentity.adapter.input.parameter.resume.path");
TransactionalStateSupport txStateSupport = new TransactionalStateSupport(resumePath);

String name="foo";
String value="bar";
txStateSupport.setAttribute(name, value, req, resp);
String value2 = (String) txStateSupport.getAttribute(name, req, resp);
System.out.println("Value directly after storing: " + value2);
if(!value.equals(value2))
  System.out.println("**** STORAGE FAILED ****");

输出:

B3E085C450 : Message{partnerRole=null, entityId='null', msg={partnerEntityID=testclient, scope=openid email profile, com.pingidentity.adapter.input.parameter.tracking.id=tid:cBAmXoOGkUCQXCSjRJ4quIlV5DE, response_type=code, redirect_uri=http://localhost.dev, sessionid=D5ZaljlkoPc6Bdv5l37IiyQikCK, client_id=testclient, com.pingidentity.plugin.instanceid=asd}}
2018-06-20 14:10:47,191 tid:4zBU2dUsYh8O-IRvXFjX3WOylLc DEBUG [org.sourceid.servlet.HttpServletRespProxy] adding lazy cookie Cookie{PF=hashedValue:yF4bj2jqUXu6jvMw0rBOVDuATWs; path=/; maxAge=-1; domain=null} replacing null
2018-06-20 14:10:47,191 tid:4zBU2dUsYh8O-IRvXFjX3WOylLc DEBUG [org.sourceid.saml20.service.impl.localmemory.InterReqStateMgmtMapImpl] setAttr(oldKey: null, newKey: yF4bj2jqUXu6jvMw0rBOVDuATWs, name: foo||h6tCJ)
2018-06-20 14:10:47,191 tid:4zBU2dUsYh8O-IRvXFjX3WOylLc DEBUG [org.sourceid.saml20.service.impl.localmemory.InterReqStateMgmtMapImpl] setAttr: new size of attribute map=3
2018-06-20 14:10:47,192 tid:4zBU2dUsYh8O-IRvXFjX3WOylLc INFO  [SystemOut] Value directly after storing: null
2018-06-20 14:10:47,192 tid:4zBU2dUsYh8O-IRvXFjX3WOylLc INFO  [SystemOut] **** STORAGE FAILED ****

有没有人对此有解决方案,或者知道此过程失败的原因?

提前致谢

这个问题也困扰了我一段时间。它有时会发生,有时不会,而且并不总是可以重现。现在终于找到了:

如果您在写入 HTTP 响应之前将某些内容存储在事务状态,它就会起作用。如果您先写入 HTTP 响应,然后尝试以事务状态存储某些内容,则会失败。如果您在写入 HTTP 响应之前将某些内容存储在事务状态,您也可以在之后写入事务状态。

观察

我观察到该问题与 PF cookie 的长度有关:它适用于 44 个字符长的 PF cookie,但它不能用于 22 个字符的 PF cookie(请注意 cookie 长度是可配置的, 但也有单长和双长的饼干)。

它也可以在 没有 任何 PF 请求 cookie 的情况下工作(这是一种罕见的情况,我不同意@Hans Z. 和@Andrew K.;-))。但是 如果 它有效,PingFederate 会在响应中设置一个 44 个字符的 PF cookie。

所以剩下的问题是:when/why PingFederate 是否设置了 44 个字符的 PF cookie?

背景

PingFederate 为每个请求维护一个内部会话 ID。 sessionID 对应于 PF cookie 的值。如果最初没有发送 PF cookie,则会创建一个新的 sessionID。因此,您在使用事务状态的请求中不需要 PF cookie

初始sessionID是一个短的(22个字符)sessionID,不适合在事务状态下存储值。如果您有一个较短的 sessionID 并尝试以事务状态存储某些内容,PingFederate 将 sessionID 扩展 为 44 个字符。因此,如果有效,您将看到一个 44 个字符的 PF 响应 cookie。

如果响应已提交,则此扩展 sessionID 的过程将失败。如果您对 response.getWriter()response.sendRedirect() 之类的响应执行任何操作,PingFederate 将“清除 cookie”。这意味着它实际上将缓存的“惰性”cookie 添加到 HTTP 响应对象,如以下日志条目所示:

DEBUG [org.sourceid.servlet.HttpServletRespProxy] flush cookies: adding Cookie{PF=hashedValue:dkxuW0rImM-votyz33kWkGGbj30; path=/; maxAge=-1; domain=null}

既然cookies已经写入,sessionID就不能再扩展了(否则会和浏览器接收到的不同步),事务状态就不行了

恕我直言,这是 PingFederate SDK 中的错误。至少这是一个应该记录在案的限制。

解决方法

重构您的代码以在写入 HTTP 响应之前使用事务状态。如果那不可能,只需在写入 HTTP 响应之前插入一行以在事务状态中存储虚拟属性。

我已经使用独立的 PF 9.3.0 实例对此进行了测试。

旁注

关于原问题:

... to make the oauth-client-id (which is available as a query parameter during the first HTTP request) accessible throughout the whole transaction.

从 PF 9.2 开始,您可以使用“跟踪的 HTTP 参数”使请求参数在整个事务中可用。有关详细信息,请参阅 release notes and the SDK documentation.