Spring SAML:由于 JSESSIONID cookie 被阻止,单点注销失败

问题描述 投票:0回答:1

我们的应用程序使用 spring-security 4.2.1 和 spring-security-saml2-core 1.10.0 实现 SAML 单点登录。 SLO 无法正常工作。当在不同的应用程序中注销时,发送给我们的 SLO 请求不会终止本地会话。 当 IdP 存储并包含在 SAML 注销请求中的 JSESSIONID cookie 被浏览器阻止时,似乎会发生这种情况。因此,Spring 无法找到给定会话的安全上下文,因此无法终止会话并返回错误消息“没有用户登录”。

在处理注销请求之前,

SecurityContextPersistenceFilter
会创建一个新上下文,因为会话 ID 丢失。

HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,
        response);
SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

try {
    SecurityContextHolder.setContext(contextBeforeChainExecution);

    chain.doFilter(holder.getRequest(), holder.getResponse());

}

接下来,

SAMLLogoutProcessingFilter.processLogout()
尝试获取安全上下文身份验证对象,该对象为空。

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
SAMLCredential credential = null;
if (auth != null) {
    credential = (SAMLCredential) auth.getCredentials();
}

由于凭证为空,

SingleLogoutProfileImpl.processLogoutRequest()
会抛出异常。

// Check whether any user is logged in
if (credential == null) {
    throw new SAMLStatusException(StatusCode.UNKNOWN_PRINCIPAL_URI, "No user is logged in");
}

我尝试的第一个修复是设置 cookie 的

SameSite
属性。之前没有设置过,因此浏览器默认为
SameSite=Lax
并在此基础上阻止 cookie。设置
SameSite=None
可以解决问题,但 如果浏览器设置为 允许 第三方 cookie。

我尝试的下一件事是

Partitioned
cookie 属性。然而,当发送注销请求时,浏览器也会阻止该 cookie,因为 cookie 被分区到 IdP 的域而不是应用程序的域。另外,截至目前,并非所有浏览器都支持分区 cookie。

也许 Spring 可以配置/实现为基于注销请求中包含的 SAML 消息找到正确的会话以进行单点注销处理。目前我们的应用程序使用

HttpSessionSecurityContextRepository
实现来查找安全上下文。

spring-security spring-saml spring-security-saml2
1个回答
0
投票

我对此提出了自己的解决方案。不幸的是,我不被允许分享代码,所以出于谨慎考虑,我不会这样做。我会尽力解释没有它的解决方案。

我编写了一个扩展

SecurityContextRepository
的类,以将安全上下文对象存储在映射中,其中密钥是 SAML 消息中的
SessionIndex
属性。该类将所有其他正常的安全上下文处理委托给我们之前使用过的
HttpSessionSecurityContextRepository

在方法

loadContext
中,我检查请求是否包含
LogoutRequest
SAML 消息。如果没有,我会调用委托存储库的
loadContext
。否则,解析的 SAML 消息可以转换为
LogoutRequest
对象,并且可以提取会话索引,我可以检查安全上下文映射是否返回具有该会话索引的安全上下文。

请注意,即使我返回在地图中找到的安全上下文,我仍然需要调用委托的

loadContext
方法,因为它也会进行请求/响应包装,如果不这样做,则会导致异常。

saveContext
方法中,我从
SAMLCredential
对象获取
Authentication
,这是从传递给该方法的
context
获得的。会话索引可以从
SAMLCredential
对象中提取,上下文可以放入映射中。在方法的最后,我总是调用委托的
saveContext
方法。

在此解决方案中,我选择在调用

loadContext
时手动解析 SAML 消息。我不确定是否可能或实际以某种方式传递现有的 SAML 处理器 bean 并使用它。这种 SAML 解析方法对我有用:http://sureshatt.blogspot.com/2012/11/how-to-read-saml-20-response-with.html

另请注意,如果您手动解析 SAML 消息:如果使用 HTTP 重定向绑定(即,如果注销请求是 GET 请求),则需要增加 SAML 有效负载。我为此使用了 Java

Inflater
对象:https://docs.oracle.com/javase/8/docs/api/java/util/zip/Inflater.html

如果您对此有任何疑问,请随时询问!

© www.soinside.com 2019 - 2024. All rights reserved.