问题
I'm working with spring-security and spring-security-saml2-service-provider with versions 5.2.0.RELEASE. I'm trying after authentication by IDP to obtain the current Assertion in order to map it to a user in our local system. I use this code to obtain the Saml2Authentication object
@Component
@Log4j
public class EventListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {
@Override
public void onApplicationEvent(InteractiveAuthenticationSuccessEvent interactiveAuthenticationSuccessEvent) {
Object principal = interactiveAuthenticationSuccessEvent.getAuthentication().getPrincipal();
Saml2Authentication authentication = (Saml2Authentication)interactiveAuthenticationSuccessEvent.getAuthentication()
But I cannot get the user. I can get the saml2 response (authentication.getSaml2Response) but I'm not sure how to obtain the assertion with the id of the user.
Really, I would like to do Retrieve Attributes and NameID from a SAML Response (XML) in the Java Code. Not sure if there is something in spring-security that can help me.
Update So after a bit of work, I get the attributes using the OpenSAML library and parsing the SAMLv2 response. I don't know if this is the correct way to do it
@Override
public void onApplicationEvent(InteractiveAuthenticationSuccessEvent interactiveAuthenticationSuccessEvent) {
Saml2Authentication authentication = (Saml2Authentication) interactiveAuthenticationSuccessEvent.getAuthentication();
try {
Document messageDoc;
BasicParserPool basicParserPool = new BasicParserPool();
basicParserPool.initialize();
InputStream inputStream = new ByteArrayInputStream(authentication.getSaml2Response().getBytes());
messageDoc = basicParserPool.parse(inputStream);
Element messageElem = messageDoc.getDocumentElement();
Unmarshaller unmarshaller = XMLObjectProviderRegistrySupport.getUnmarshallerFactory().getUnmarshaller(messageElem);
XMLObject samlObject = unmarshaller.unmarshall(messageElem);
Response response = (Response) samlObject;
response.getAssertions().forEach(assertion -> {
assertion.getAttributeStatements().forEach(attributeStatement ->
{
attributeStatement.getAttributes().forEach(attribute -> {
log.error("Names:" + attribute.getName() + getAttributesList(attribute.getAttributeValues()));
});
});
});
} catch (Exception e) {
log.error(e);
}
}
private List<String> getAttributesList(Collection<XMLObject> collection) {
return collection.stream().map(this::getAttributeValue)
.collect(Collectors.toList());
}
private String getAttributeValue(XMLObject attributeValue) {
return attributeValue == null ?
null :
attributeValue instanceof XSString ?
getStringAttributeValue((XSString) attributeValue) :
attributeValue instanceof XSAnyImpl ?
getAnyAttributeValue((XSAnyImpl) attributeValue) :
attributeValue.toString();
}
private String getStringAttributeValue(XSString attributeValue) {
return attributeValue.getValue();
}
private String getAnyAttributeValue(XSAnyImpl attributeValue) {
return attributeValue.getTextContent();
}
回答1:
By default Spring SAML Security is using the value of the NameID in the Subject element to set the 'username'. If 'transient NameID format', the value has to be a different/unique one for every SSO flow per SAML spec.
You can implement your own UserDetailsService
which implements org.springframework.security.saml.userdetails.SAMLUserDetailsService
in method loadUserBySAML
you can extract the SAML attributes
@Override
public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException {
final List<Attribute> attributesFromAttributeStatement = credential.getAttributes();
final String userName = getUserNameValueFromAttribute(attributesFromAttributeStatement);
// if needed calculate authorities
final List<GrantedAuthority> grantedAuthorities = getGrantedAuthorities();
final User authenticatedUser = new User(userName, "", grantedAuthorities);
return authenticatedUser;
}
来源:https://stackoverflow.com/questions/58400571/spring-security-saml2-how-to-obtain-the-current-user