警告巨大的帖子!
今年年初我发布了这个问题:Orbeon Single sign-on to SAP Netweaver
经过几个月的其他工作,我再次查看并听取了 Orbeons 的建议并开始调试 Scala 代码。
这一切都是通过 CE 源代码 github (4.4CE) 完成的。我查看的文件是 Connection.scala https://github.com/orbeon/orbeon-forms/blob/master/src/main/scala/org/orbeon/oxf/util/Connection.scala
首先要注意的是 SAP Netweaver AS 处理 sessionid 与 Tomcat 有点不同。sessionid 和 JSESSIONID 不相同。如上一篇文章所示,sessionid 是 JSESSIONID 的较短版本,在 Tomcat 中它们是相同的。
1.
让我们看一下方法 sessionCookieFromIncoming (537): 在这个方法中,我发现了 Netweaver 的第一个问题:
def requestedSessionIdMatches =
Option(externalContext.getSession(false)) exists { session ⇒
val requestedSessionId = externalContext.getRequest.getRequestedSessionId
session.getId == requestedSessionId
}
val cookies = Option(nativeRequest.getCookies) getOrElse Array.empty[Cookie]
if (requestedSessionIdMatches && cookies.nonEmpty) {
代码行:
session.getId == requestedSessionId
这些在 Netweaver 上是不一样的(就像我在 session 中所说的是 JSESSIONID 的较短版本)。所以我对修复的第一个想法是这样的(我不是 Scala 程序员,所以请原谅一些糟糕的代码):
requestedSessionId contains session.getId
为了调试,我添加了一些额外的代码。我从来没有启用调试,所以我只是在控制台上转储了所有相同的方法
val pairsToForward =
for {
cookie ← cookies
if cookiesToForward.contains(cookie.getName)
} yield
cookie.getName + '=' + cookie.getValue
if (pairsToForward.nonEmpty) {
// Multiple cookies in the header, separated with ";"
val cookieHeaderValue = pairsToForward mkString "; "
debug("forwarding cookies", Seq(
"cookie" → cookieHeaderValue,
"requested session id" → externalContext.getRequest.getRequestedSessionId))
System.out.println("\nForwarding cookies " + "cookie " → cookieHeaderValue + "\nRequested session id " → externalContext.getRequest.getRequestedSessionId)
Some("cookie" → Array(cookieHeaderValue))
控制台输出:
forwarding cookies (cookie , MYSAPSSO2=AjExMDAgABBwb3J0YWw6ZV9nYW1zbTAxiAAHZGVmYXVsdAEACUVfR0FNU00wMQIAAzAwMAMAA1NQRAQADDIwMTMxMTMwMjEyMAUABAAAAAgKAAlFX0dBTVNNMDH%2FAQYwggECBgkqhkiG9w0BBwKggfQwgfECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHATGB0TCBzgIBATAkMBsxCzAJBgNVBAYTAk5MMQwwCgYDVQQDEwNTUEQCBQCEogh2MAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xMzExMzAyMTIwMzdaMCMGCSqGSIb3DQEJBDEWBBSryP8YWrWBPrzQBMyIypyfgGJT2TAJBgcqhkjOOAQDBC4wLAIUaMRLpG%2FxZYhzRIbyXzibMJJIGNcCFF4mmIESPh9o7kd7k46NNkr9ESLg;
JSESSIONID=TCaFUY3kaqppP-IakFa0KDRgeOKqQgGScngA_SAP158n6gVEgGH7sItNCAOyfIFO)(
Requested session id ,TCaFUY3kaqppP-IakFa0KDRgeOKqQgGScngA_SAP158n6gVEgGH7sItNCAOyfIFO)
这看起来不错。我得到了我的 SSO cookie 和正确长度的 JSESSIONID
有一些调试功能,但我将它们转储到控制台参见代码 523 行。 sessionID 和传入会话 cookie (JSESSIONID) 之间的区别显然是这样的结果:
Debug sessie:(
new session,false)(
session id,TCaFUY3kaqppP-IakFa0KDRgeOKqQgGScngA_SAP)(
requested session id,TCaFUY3kaqppP-IakFa0KDRgeOKqQgGScngA_SAP158n6gVEgGH7sItNCAOyfIFO)(
session cookie name,JSESSIONID)(
incoming session cookies,TCaFUY3kaqppP-IakFa0KDRgeOKqQgGScngA_SAP158n6gVEgGH7sItNCAOyfIFO)(
incoming session headers,saplb_*=(J2EE7893620)7893650; MYSAPSSO2=AjExMDAgABBwb3J0YWw6ZV9nYW1zbTAxiAAHZGVmYXVsdAEACUVfR0FNU00wMQIAAzAwMAMAA1NQRAQADDIwMTMxMTMwMjEyMAUABAAAAAgKAAlFX0dBTVNNMDH%2FAQYwggECBgkqhkiG9w0BBwKggfQwgfECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHATGB0TCBzgIBATAkMBsxCzAJBgNVBAYTAk5MMQwwCgYDVQQDEwNTUEQCBQCEogh2MAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xMzExMzAyMTIwMzdaMCMGCSqGSIb3DQEJBDEWBBSryP8YWrWBPrzQBMyIypyfgGJT2TAJBgcqhkjOOAQDBC4wLAIUaMRLpG%2FxZYhzRIbyXzibMJJIGNcCFF4mmIESPh9o7kd7k46NNkr9ESLg; JSESSIONID=TCaFUY3kaqppP-IakFa0KDRgeOKqQgGScngA_SAP158n6gVEgGH7sItNCAOyfIFO)
2.
返回到 def buildConnectionHeaders (398)。在方法的最后,Orbeon 构建了一个带有转发 cookie 的新标头(我希望这是正确的)。
headersToForwardLowercase.toMap ++ explicitHeadersLowercase ++ newCookieHeader ++ tokenHeader
所以在 newCookieHeader 中应该是 MYSAPSSO2 cookie 和一个有效的 JSESSIONID
要检查我是否添加了此代码:来自 Orbeon (441) 的代码:
val newCookieHeader = credentials match {
case None ⇒ sessionCookieHeader(externalContext)
case Some(_) ⇒ None
}
为了打印这个值,我添加了这行代码:
var map = newCookieHeader.toMap
println(map("cookie")(0));
令我惊讶的是,控制台向我展示了这个:
JSESSIONID=TCaFUY3kaqppP-IakFa0KDRgeOKqQgGScngA_SAP
不是我所希望的。那么这怎么可能呢?这里和两者之间没有什么特别的事情发生。我知道该值不是来自 sessionCookieFromGuess 方法,因为显示正确值的打印语句位于 sessionCookieFromIncoming 中。
3.
所以我开始研究并想出了这个(同样不是 Scala 代码的最佳示例)。我之前将此代码添加到 buildConnectionHeaders 方法中
// Don't forward headers for which a value is explicitly passed by the caller, so start with headersToForward
// New cookie header, if present, overrides any existing cookies
headersToForwardLowercase.toMap ++ explicitHeadersLowercase ++ newCookieHeader ++ tokenHeader
我的代码。我从 Orbeon 代码中提取了一些零碎的东西并粘贴了它们。然后我从 externalContext 中获取 JSESSIONID 和 MYSAPSSO2 并构建我自己的 newCookieHeader
val requestOption = Option(externalContext.getRequest)
val nativeRequestOption =
requestOption flatMap
(r ⇒ Option(r.getNativeRequest)) collect
{ case r: HttpServletRequest ⇒ r }
val MYSAP =
for {
nativeRequest ← nativeRequestOption.toList
cookies ← Option(nativeRequest.getCookies).toList
cookie ← cookies
if cookie.getName == "MYSAPSSO2"
} yield
cookie.getValue
val MYJS =
for {
nativeRequest ← nativeRequestOption.toList
cookies ← Option(nativeRequest.getCookies).toList
cookie ← cookies
if cookie.getName == "JSESSIONID"
} yield
cookie.getValue
var values = "MYSAPSSO2=" + MYSAP(0) + "; JSESSIONID=" + MYJS(0)
def test : Option[(String, Array[String])] = {
Some("cookie" → Array(values))
}
之后,我将测试功能转储到控制台并显示此结果(id 不同,因为它是一个新部署的应用程序:
MYSAPSSO2=AjExMDAgABBwb3J0YWw6ZV9nYW1zbTAxiAAHZGVmYXVsdAEACUVfR0FNU00wMQIAAzAwMAMAA1NQRAQADDIwMTMxMTMwMjEyMAUABAAAAAgKAAlFX0dBTVNNMDH%2FAQYwggECBgkqhkiG9w0BBwKggfQwgfECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHATGB0TCBzgIBATAkMBsxCzAJBgNVBAYTAk5MMQwwCgYDVQQDEwNTUEQCBQCEogh2MAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xMzExMzAyMTIwMzdaMCMGCSqGSIb3DQEJBDEWBBSryP8YWrWBPrzQBMyIypyfgGJT2TAJBgcqhkjOOAQDBC4wLAIUaMRLpG%2FxZYhzRIbyXzibMJJIGNcCFF4mmIESPh9o7kd7k46NNkr9ESLg;
JSESSIONID=TCaFUY3kaqppP-IakFa0KDRgeOKqQgGScngA_SAP158n6gVEgGH7sItNCAOyfIFO
所以问题就来了,为什么示例 3 中的代码在示例 2 中不起作用。我希望 Orbeon 可以帮助我追踪这个问题的根源,并植入一个更 Netweaver 友好的 cookie forwardig 方式,如示例 1 所示。