Spring SAML 与 WSO2 身份服务器集成,无法识别 SAML 消息
Spring SAML integration with WSO2 Identity server, SAML Message ID not reconised
我采用了 Spring SAML 示例(参见第 4.2 in this guide 节),它与开源登录页面 SSO 一起使用,并尝试添加支持以使用 WSO2 身份服务器作为额外的 IDP服务。
为此,我通过为 IS 添加一个元数据 xml 文件来更改 spring SAML 示例项目,并将 IS 元数据的条目添加到 securityContext.xml.
在运行 spring 应用程序时,我现在可以看到一个使用 IS 登录的选项,当我被重定向到 WSO2 时,我可以成功登录。然而,spring 应用程序在 IS SAML 响应上抛出异常,因为它与 InResponseToField 不匹配。
2015-01-05 09:54:12,845 line="org.springframework.security.saml.log.SAMLDefaultLogger.log(SAMLDefaultLogger.java:127)" thread="http-nio-8080-exec-4" class="org.springframework.security.saml.log.SAMLDefaultLogger" AuthNResponse;FAILURE;0:0:0:0:0:0:0:1;com:vdenotaris:spring:sp;localhost;;;org.opensaml.common.SAMLException: InResponseToField of the Response doesn't correspond to sent message ae2dab0fb8b0g8e49971b91a73e91i
从调试应用程序来看,响应消息似乎未被识别为与请求消息属于同一会话。我说从这 2 条日志消息中,第 1 条是在发送 AuthRequest 时记录的,第 2 条是在收到响应时记录的:
2015-01-05 09:53:20,867 line="org.springframework.security.saml.storage.HttpSessionStorage.storeMessage(HttpSessionStorage.java:93)" thread="http-nio-8080-exec-1" class="org.springframework.security.saml.storage.HttpSessionStorage" Storing message ae2dab0fb8b0g8e49971b91a73e91i to session 26D3B7D9E33F26A7A5092BF6909B9D13
...
2015-01-05 09:54:10,731 line="org.springframework.security.saml.storage.HttpSessionStorage.retrieveMessage(HttpSessionStorage.java:117)" thread="http-nio-8080-exec-4" class="org.springframework.security.saml.storage.HttpSessionStorage" Message ae2dab0fb8b0g8e49971b91a73e91i not found in session BBF256F284F55D774E6997600E9B3388
IS SAML 响应是:
<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://localhost:8080/saml/SSO" ID="adlbklpnldoanfphalcaahhacooinnldcejjjioe" InResponseTo="ae2dab0fb8b0g8e49971b91a73e91i" IssueInstant="2015-01-05T09:53:38.063Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">localhost</saml2:Issuer>
<saml2p:Status>
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="ebhfkdhlgbhclcklefjigfddoikklhjlanlbolel" IssueInstant="2015-01-05T09:53:38.065Z" Version="2.0">
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">localhost</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">smit005</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="ae2dab0fb8b0g8e49971b91a73e91i" NotOnOrAfter="2015-01-05T09:58:38.063Z" Recipient="http://localhost:8080/saml/SSO"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2015-01-05T09:53:38.065Z" NotOnOrAfter="2015-01-05T09:58:38.063Z">
<saml2:AudienceRestriction>
<saml2:Audience>com:vdenotaris:spring:sp</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2015-01-05T09:53:38.068Z" SessionIndex="406d4530-6fcf-4edf-b876-a68de4b4ea79">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement/>
</saml2:Assertion>
</saml2p:Response>
作为参考,我附上了我为 WSO2 IS 添加的元数据 xml 文件(我必须给它一个 'localhost' 的实体 ID,因为这是 WSO2 IS 坚持要返回的(它使用主机默认名称))。
<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
entityID="localhost"
validUntil="2023-09-23T06:57:15.396Z">
<md:IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" >
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIICNTCCAZ6gAwIBAgIES343gjANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJVUzELMAkGA1UE
CAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxDTALBgNVBAoMBFdTTzIxEjAQBgNVBAMMCWxv
Y2FsaG9zdDAeFw0xMDAyMTkwNzAyMjZaFw0zNTAyMTMwNzAyMjZaMFUxCzAJBgNVBAYTAlVTMQsw
CQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzENMAsGA1UECgwEV1NPMjESMBAGA1UE
AwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUp/oV1vWc8/TkQSiAvTou
sMzOM4asB2iltr2QKozni5aVFu818MpOLZIr8LMnTzWllJvvaA5RAAdpbECb+48FjbBe0hseUdN5
HpwvnH/DW8ZccGvk53I6Orq7hLCv1ZHtuOCokghz/ATrhyPq+QktMfXnRS4HrKGJTzxaCcU7OQID
AQABoxIwEDAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADgYEAW5wPR7cr1LAdq+IrR44i
QlRG5ITCZXY9hI0PygLP2rHANh+PYfTmxbuOnykNGyhM6FjFLbW2uZHQTY1jMrPprjOrmyK5sjJR
O4d1DeGHT/YnIjs9JogRKv4XHECwLtIVdAbIdWHEtVZJyMSktcyysFcvuhPQK8Qc/E/Wq8uHSCo=</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://localhost:9443/samlsso" ResponseLocation="https://localhost:9443/samlsso"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://localhost:9443/samlsso"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://localhost:9443/samlsso"/>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
</md:IDPSSODescriptor>
</md:EntityDescriptor>
根据要求,我在 dropbox 上保存了浏览器 HTTP 消息的日志。
Spring SAML 和您的 IDP WSO2 服务器都部署在同一域 - localhost。这是发生了什么:
- Spring SAML 创建一个 HTTP 会话 (JSESSIONID -
82F3ECD1A1E4F9B7DB0134F3129267A5
) 并初始化单点登录
- WSO2 接受请求并对用户进行身份验证,但创建自己的会话 (JSESSIONID -
C34B21931C53080487B5B9BA6EB490D2
) 并将用户重定向回 Spring SAML
- container 运行 Spring SAML 收到带有 JSESSIONID (
C34B21931C53080487B5B9BA6EB490D2
) 的 cookie,但由于它无法识别此类会话创建一个新的 (E712A8422009613F6FD3901327690726
)
- Spring SAML 尝试根据原始请求验证收到的 SAML 消息,但无法找到它,因为原始会话现已消失
解决此问题的最简单方法是更改 Spring SAML 或 WSO2 的会话 cookie 名称。您还可以在不同的域上部署您的应用程序(例如,通过在主机文件中为本地主机指定一个别名 - /etc/hosts
或 %systemroot%\system32\drivers\etc\hosts
)
我采用了 Spring SAML 示例(参见第 4.2 in this guide 节),它与开源登录页面 SSO 一起使用,并尝试添加支持以使用 WSO2 身份服务器作为额外的 IDP服务。 为此,我通过为 IS 添加一个元数据 xml 文件来更改 spring SAML 示例项目,并将 IS 元数据的条目添加到 securityContext.xml.
在运行 spring 应用程序时,我现在可以看到一个使用 IS 登录的选项,当我被重定向到 WSO2 时,我可以成功登录。然而,spring 应用程序在 IS SAML 响应上抛出异常,因为它与 InResponseToField 不匹配。
2015-01-05 09:54:12,845 line="org.springframework.security.saml.log.SAMLDefaultLogger.log(SAMLDefaultLogger.java:127)" thread="http-nio-8080-exec-4" class="org.springframework.security.saml.log.SAMLDefaultLogger" AuthNResponse;FAILURE;0:0:0:0:0:0:0:1;com:vdenotaris:spring:sp;localhost;;;org.opensaml.common.SAMLException: InResponseToField of the Response doesn't correspond to sent message ae2dab0fb8b0g8e49971b91a73e91i
从调试应用程序来看,响应消息似乎未被识别为与请求消息属于同一会话。我说从这 2 条日志消息中,第 1 条是在发送 AuthRequest 时记录的,第 2 条是在收到响应时记录的:
2015-01-05 09:53:20,867 line="org.springframework.security.saml.storage.HttpSessionStorage.storeMessage(HttpSessionStorage.java:93)" thread="http-nio-8080-exec-1" class="org.springframework.security.saml.storage.HttpSessionStorage" Storing message ae2dab0fb8b0g8e49971b91a73e91i to session 26D3B7D9E33F26A7A5092BF6909B9D13
...
2015-01-05 09:54:10,731 line="org.springframework.security.saml.storage.HttpSessionStorage.retrieveMessage(HttpSessionStorage.java:117)" thread="http-nio-8080-exec-4" class="org.springframework.security.saml.storage.HttpSessionStorage" Message ae2dab0fb8b0g8e49971b91a73e91i not found in session BBF256F284F55D774E6997600E9B3388
IS SAML 响应是:
<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://localhost:8080/saml/SSO" ID="adlbklpnldoanfphalcaahhacooinnldcejjjioe" InResponseTo="ae2dab0fb8b0g8e49971b91a73e91i" IssueInstant="2015-01-05T09:53:38.063Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">localhost</saml2:Issuer>
<saml2p:Status>
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="ebhfkdhlgbhclcklefjigfddoikklhjlanlbolel" IssueInstant="2015-01-05T09:53:38.065Z" Version="2.0">
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">localhost</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">smit005</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="ae2dab0fb8b0g8e49971b91a73e91i" NotOnOrAfter="2015-01-05T09:58:38.063Z" Recipient="http://localhost:8080/saml/SSO"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2015-01-05T09:53:38.065Z" NotOnOrAfter="2015-01-05T09:58:38.063Z">
<saml2:AudienceRestriction>
<saml2:Audience>com:vdenotaris:spring:sp</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2015-01-05T09:53:38.068Z" SessionIndex="406d4530-6fcf-4edf-b876-a68de4b4ea79">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement/>
</saml2:Assertion>
</saml2p:Response>
作为参考,我附上了我为 WSO2 IS 添加的元数据 xml 文件(我必须给它一个 'localhost' 的实体 ID,因为这是 WSO2 IS 坚持要返回的(它使用主机默认名称))。
<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
entityID="localhost"
validUntil="2023-09-23T06:57:15.396Z">
<md:IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" >
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIICNTCCAZ6gAwIBAgIES343gjANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJVUzELMAkGA1UE
CAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxDTALBgNVBAoMBFdTTzIxEjAQBgNVBAMMCWxv
Y2FsaG9zdDAeFw0xMDAyMTkwNzAyMjZaFw0zNTAyMTMwNzAyMjZaMFUxCzAJBgNVBAYTAlVTMQsw
CQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzENMAsGA1UECgwEV1NPMjESMBAGA1UE
AwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUp/oV1vWc8/TkQSiAvTou
sMzOM4asB2iltr2QKozni5aVFu818MpOLZIr8LMnTzWllJvvaA5RAAdpbECb+48FjbBe0hseUdN5
HpwvnH/DW8ZccGvk53I6Orq7hLCv1ZHtuOCokghz/ATrhyPq+QktMfXnRS4HrKGJTzxaCcU7OQID
AQABoxIwEDAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADgYEAW5wPR7cr1LAdq+IrR44i
QlRG5ITCZXY9hI0PygLP2rHANh+PYfTmxbuOnykNGyhM6FjFLbW2uZHQTY1jMrPprjOrmyK5sjJR
O4d1DeGHT/YnIjs9JogRKv4XHECwLtIVdAbIdWHEtVZJyMSktcyysFcvuhPQK8Qc/E/Wq8uHSCo=</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://localhost:9443/samlsso" ResponseLocation="https://localhost:9443/samlsso"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://localhost:9443/samlsso"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://localhost:9443/samlsso"/>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
</md:IDPSSODescriptor>
</md:EntityDescriptor>
根据要求,我在 dropbox 上保存了浏览器 HTTP 消息的日志。
Spring SAML 和您的 IDP WSO2 服务器都部署在同一域 - localhost。这是发生了什么:
- Spring SAML 创建一个 HTTP 会话 (JSESSIONID -
82F3ECD1A1E4F9B7DB0134F3129267A5
) 并初始化单点登录 - WSO2 接受请求并对用户进行身份验证,但创建自己的会话 (JSESSIONID -
C34B21931C53080487B5B9BA6EB490D2
) 并将用户重定向回 Spring SAML - container 运行 Spring SAML 收到带有 JSESSIONID (
C34B21931C53080487B5B9BA6EB490D2
) 的 cookie,但由于它无法识别此类会话创建一个新的 (E712A8422009613F6FD3901327690726
) - Spring SAML 尝试根据原始请求验证收到的 SAML 消息,但无法找到它,因为原始会话现已消失
解决此问题的最简单方法是更改 Spring SAML 或 WSO2 的会话 cookie 名称。您还可以在不同的域上部署您的应用程序(例如,通过在主机文件中为本地主机指定一个别名 - /etc/hosts
或 %systemroot%\system32\drivers\etc\hosts
)