Spring Security SAML 一次登录全局单次注销 LogoutRequest 解析问题 [英] Spring Security SAML One Login Global Single Logout LogoutRequest Parsing Issue

查看:127
本文介绍了Spring Security SAML 一次登录全局单次注销 LogoutRequest 解析问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过一次登录实现 Spring Security SAML.我已经设置了所有配置文件并设置了元数据.

如果我从我登录的同一个应用程序注销,我能够进行登录工作并且注销正在工作.在这种情况下,我从 SAML IDP 获得 LogoutResponse 并且 Spring Security 能够解析和处理

<块引用>

http://localhost:8080/web/saml/SingleLogout?SAMLResponse=................

问题是当我在两个应用程序中登录时,目前我登录到 One Login 管理控制台,有一个指向我的应用程序的链接,我点击它,我可以直接在我的应用程序中登录,现在当我从一个登录管理控制台,我的应用程序获得 LogoutRequest.

<块引用>

http://localhost:8080/web/saml/SingleLogout?SAMLRequest=.........

Spring Security 会很好地解析它并将对象传递给验证检查逻辑.

org.springframework.security.saml.websso.processLogoutRequest(SAMLMessageContext 上下文,SAMLCredential 凭证)

此方法有以下检查.

//如果需要,请确保请求已通过身份验证,身份验证是绑定处理的一部分if (!context.isInboundSAMLMessageAuthenticated() && context.getLocalExtendedMetadata().isRequireLogoutRequestSigned()) {throw new SAMLStatusException(StatusCode.REQUEST_DENIED_URI, "LogoutRequest 需要由实体策略签名");}

我尝试跟踪跟踪,但上下文对象的字段 inboundSAMLMessageAuthenticated 从未设置为 true.上述检查失败并抛出异常.

在调试模式下,我明确地将该值设置为 true,它继续进行,但还有一个问题.

同样的方法还有一个检查.

尝试{//如果 NameId 与当前登录的用户不对应,则失败NameID nameID = getNameID(context, logoutRequest);if (nameID == null || !equalsNameID(credential.getNameID(), nameID)) {throw new SAMLStatusException(StatusCode.UNKNOWN_PRINCIPAL_URI, "请求的 NameID 无效");}} catch (DecryptionException e) {throw new SAMLStatusException(StatusCode.RESPONDER_URI, "无法解密 NameID", e);}

方法equalsNameId如下.

private boolean equalsNameID(NameID a, NameID b) {布尔等于 = !differ(a.getSPProvidedID(), b.getSPProvidedID());等于 = 等于 &&!differ(a.getValue(), b.getValue());等于 = 等于 &&!differ(a.getFormat(), b.getFormat());等于 = 等于 &&!differ(a.getNameQualifier(), b.getNameQualifier());等于 = 等于 &&!differ(a.getSPNameQualifier(), b.getSPNameQualifier());等于 = 等于 &&!differ(a.getSPProvidedID(), b.getSPProvidedID());返回等于;}

<块引用>

这里它在不同(a.getFormat(), b.getFormat())上失败

问题

我不确定是不是我遗漏了什么,有点迷失在哪里可以检查以解决这个问题.

我的单点注销绑定是HTTP-Redirect.

如果提供指针将不胜感激.如果需要更多信息,请告诉我.

感谢您抽出时间.

堆栈(旧版应用程序):

春季 3.0.6

Spring 安全 3.1.2

Spring 安全 SAML 1.0.0

Tomcat 7.x

解决方案

在原帖发布两年后遇到了这个,我不得不做一些进一步的研究.关于 SAML 规范,我还有一些阅读要做,但我想我在 SAML 2.0 勘误表中找到了一个关于 NameIDType 结构的条目,它是 NameID 和颁发者的基础.此类型中的所有四个元素都是可选的.OneLogin 似乎遵循此文档,并且不会在 SingleLogout 请求中发送 NameID.Format.

因此,inboundMessage 的 nameID 为空格式,而凭证的 nameID 的格式为urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress".这就是导致 getFormat 行返回 false 并使整个检查失败的原因.

I am implementing Spring Security SAML with One Login. I have set all the configuration files and meta data is set.

I am able to get login work and logout is working if I logoff from the same application I logged in. In this scenario from SAML IDP I get LogoutResponse and Spring Security is able to parse and process it.

http://localhost:8080/web/saml/SingleLogout?SAMLResponse=..............

Problem is when I login in two applications, currently I login to One Login admin console, there is a link to my app, I click on it and I am able to login directly in my application, now when I log off from One Login admin console, my application gets LogoutRequest.

http://localhost:8080/web/saml/SingleLogout?SAMLRequest=.........

Spring Security parses it fine and passes the object to a validation check logic.

org.springframework.security.saml.websso.processLogoutRequest(SAMLMessageContext context, SAMLCredential credential)

This method has following check.

// Make sure request was authenticated if required, authentication is done as part of the binding processing
        if (!context.isInboundSAMLMessageAuthenticated() && context.getLocalExtendedMetadata().isRequireLogoutRequestSigned()) {
            throw new SAMLStatusException(StatusCode.REQUEST_DENIED_URI, "LogoutRequest is required to be signed by the entity policy");
        }

I tried to follow the trace but the context object's field inboundSAMLMessageAuthenticated is never set to true. The above check fails and exception is thrown.

In debug mode I explicitly chencged the value to true, it went ahead but there is one more issue.

In the same method there is another check.

try {
            // Fail if NameId doesn't correspond to the currently logged user
            NameID nameID = getNameID(context, logoutRequest);
            if (nameID == null || !equalsNameID(credential.getNameID(), nameID)) {
                throw new SAMLStatusException(StatusCode.UNKNOWN_PRINCIPAL_URI, "The requested NameID is invalid");
            }
        } catch (DecryptionException e) {
            throw new SAMLStatusException(StatusCode.RESPONDER_URI, "The NameID can't be decrypted", e);
        }

The method equalsNameId is as follows.

private boolean equalsNameID(NameID a, NameID b) {
        boolean equals = !differ(a.getSPProvidedID(), b.getSPProvidedID());
        equals = equals && !differ(a.getValue(), b.getValue());
        equals = equals && !differ(a.getFormat(), b.getFormat());
        equals = equals && !differ(a.getNameQualifier(), b.getNameQualifier());
        equals = equals && !differ(a.getSPNameQualifier(), b.getSPNameQualifier());
        equals = equals && !differ(a.getSPProvidedID(), b.getSPProvidedID());
        return equals;
    }

Here it fails on differ(a.getFormat(), b.getFormat())

Question

I am not sure is there something I am missing, kind of lost where exactly to check to tackle this issue.

My binding for Single Logout is HTTP-Redirect.

Would appreciate if pointers are provided. Let me know if more information is required.

Thanks for time.

Stack (Legacy Application):

Spring 3.0.6

Spring Security 3.1.2

Spring Security SAML 1.0.0

Tomcat 7.x

解决方案

Having encountered this two years after the original post, I had to do some further research. I still have some reading to do regarding the SAML specifications, but I think I found an entry in SAML 2.0 Errata on the structure of the NameIDType which underlies the NameID and Issuer. All four elements in this type are optional. OneLogin appears to be following this document and does not send a NameID.Format in the SingleLogout request.

So, the inboundMessage has a nameID with a null format while the credential's nameID has a format of "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress". This is what causes the getFormat line to return false and fail the entire check.

这篇关于Spring Security SAML 一次登录全局单次注销 LogoutRequest 解析问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆