Iam using spring-saml implementation. In the class WebSSOProfileConsumerImpl, I could find the following lines of code which checks for nameId in the assertion of the SAML response.
NameID nameID;
if (subject.getEncryptedID() != null) {
Assert.notNull(context.getLocalDecrypter(), "Can't decrypt NameID, no decrypter is set in the context");
nameID = (NameID) context.getLocalDecrypter().decrypt(subject.getEncryptedID());
} else {
nameID = subject.getNameID();
}
Based on the code, its clear that the nameId should be part of the subject. But most of the IDP's including the one that I am using mention that nameId could be part of the subject/attribute. Seems that there are a few implementations which accept nameId in subject just like SimpleSAMLPHP.
The subject which I am receiving is as follows and does not have nameId enclosed
<saml2:Subject>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData Address="91.X.X.X" InResponseTo="XXXX" NotOnOrAfter="2014-10-10T10:34:26.619Z" Recipient="http://localhost:8080/XXXX/saml/SSO"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
However, there is an attribute which has a nameId as its attribute value. Why cant this be used instead of the one in the subject.
<saml2:Attribute FriendlyName="testID" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue>
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" NameQualifier="https://XXXX/idp/shibboleth" SPNameQualifier="urn:XX:XX:XX">XXXXXXXXXXXXXXXXX=
</saml2:NameID>
</saml2:AttributeValue>
</saml2:Attribute>
Can anyone explain the reason behind nameId being part of only subject in spring-saml implementation.
@vschafer Is there a way of customizing the securityContext.xml to choose nameId which is part of a specific attribute and not from subject?
Spring SAML currently requires NameID
to be present. Changing this would require code changes and cannot be currently done with configuration only. Please feel free to open a feature request for changing this in Spring SAML Jira.
We had a similar scenario with ADFS 3.0. This particular configuration of ADFS didn't supply NameId at all. We implemented a workaround by requesting an UPN claim from ADFS, and then using that as NameId. A pluggable NameIdResolver would be nice though, @vschafer.
Code for workaround if anyone's interested:
public class ClaimConstants {
public static final String UPN = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn";
}
public class NameIdWebSSOProfileConsumer extends WebSSOProfileConsumerImpl {
@Override
protected void verifySubject(Subject subject, AuthnRequest request, SAMLMessageContext context) throws SAMLException, DecryptionException {
super.verifySubject(subject, request, context);
Response response = (Response) context.getInboundSAMLMessage();
for (EncryptedAssertion ea : response.getEncryptedAssertions()) {
Assertion assertion = context.getLocalDecrypter().decrypt(ea);
for (Statement statement : assertion.getStatements()) {
if (statement instanceof AttributeStatementImpl) {
for (Attribute attribute : ((AttributeStatementImpl) statement).getAttributes()) {
if (ClaimConstants.UPN.equals(attribute.getName())) {
NameID nameId = new NameIDBuilder().buildObject();
XSAnyImpl xmlObject = (XSAnyImpl) attribute.getAttributeValues().get(0);
nameId.setValue(xmlObject.getTextContent());
//noinspection unchecked
context.setSubjectNameIdentifier(nameId);
return;
}
}
}
}
}
}
And then use in Spring as normal:
<bean id="webSSOprofileConsumer" class="com.example.NameIdWebSSOProfileConsumer"/>
来源:https://stackoverflow.com/questions/26297938/samlexception-nameid-element-must-be-present-as-part-of-the-subject-in-the-resp