Я взял пример Spring SAML (см. Раздел 4.2 in this guide), который работает с системой единого входа на странице входа с открытым исходным кодом, и попытался добавить поддержку использования WSO2 Identity Server в качестве дополнительной службы IDP. Для этого я изменил образец проекта Spring SAML, добавив XML-файл метаданных для IS, и добавил запись для метаданных 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
При отладке приложения выясняется, что ответное сообщение не распознается как принадлежащее тому же сеансу, что и сообщение запроса. Я говорю, что из этих двух сообщений журнала первое регистрируется при отправке AuthRequest, а второе - при получении ответа:
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>
Для справки я прилагаю XML-файл метаданных, который я добавил для WSO2 IS (мне пришлось дать ему entityID 'localhost', поскольку 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>
По запросу я сохранил журнал HTTP-сообщений браузера в dropbox.