spring-security saml2:如何获取当前用户?
Posted
技术标签:
【中文标题】spring-security saml2:如何获取当前用户?【英文标题】:spring-security saml2 : How to obtain the current user? 【发布时间】:2020-02-12 11:35:20 【问题描述】:我正在使用版本为 5.2.0.RELEASE 的 spring-security 和 spring-security-saml2-service-provider。我正在尝试通过 IDP 进行身份验证以获取当前断言,以便将其映射到我们本地系统中的用户。 我使用此代码获取 Saml2Authentication 对象
@Component
@Log4j
public class EventListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent>
@Override
public void onApplicationEvent(InteractiveAuthenticationSuccessEvent interactiveAuthenticationSuccessEvent)
Object principal = interactiveAuthenticationSuccessEvent.getAuthentication().getPrincipal();
Saml2Authentication authentication = (Saml2Authentication)interactiveAuthenticationSuccessEvent.getAuthentication()
但我无法获取用户。我可以获得 saml2 响应(authentication.getSaml2Response),但我不确定如何获取带有用户 ID 的断言。
真的,我想在 Java 代码中做Retrieve Attributes and NameID from a SAML Response (XML) 。不确定 spring-security 中是否有可以帮助我的东西。
更新 因此,经过一番工作,我使用 OpenSAML 库获取属性并解析 SAMLv2 响应。我不知道这是否是正确的做法
@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();
【问题讨论】:
“用户”对您意味着什么? SAML 断言可以包含一个主题(具有 NameID 格式),它可以在 AttributeStatement 中包含 SAML 属性。如果使用“瞬态 NameID 格式”,则主题将是唯一的字符串。请完善您的问题。 我想获取一些属性以识别已登录的用户。例如,我可以在响应中获取 NameID,但每次登录都会更改(我使用 simplesamlphp 作为 IdP),。我想获得一些属性,它对每个用户都是唯一的,这样我就可以在系统中识别它。感谢您的回复! @drizzt.dourden 一旦您的 IDP 对请求进行身份验证,它将根据合同向您发送一些属性作为响应。你没有得到这些属性吗? 是的,我得到了属性。问题是我找不到任何方法可以为我提供 saml-security 中的所有属性。所以最后,我得到了解析 XML 响应的属性。 @drizzt.dourden ***.com/a/62456724/10479742 【参考方案1】:默认情况下,Spring SAML Security 使用 Subject 元素中 NameID 的值来设置“用户名”。如果是“瞬态 NameID 格式”,则对于每个 SAML 规范的每个 SSO 流,该值必须是不同/唯一的。
您可以实现自己的UserDetailsService
,它在方法loadUserBySAML
中实现org.springframework.security.saml.userdetails.SAMLUserDetailsService
,您可以提取SAML 属性
@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;
【讨论】:
感谢您的来信;之后,在我的应用程序中,我如何检索在 loadUserBySAML 方法中生成的用户(在本例中为 User authenticatedUser)?我认为使用 Spring(和 Spring Boot)可以使用注释......以上是关于spring-security saml2:如何获取当前用户?的主要内容,如果未能解决你的问题,请参考以下文章
将 java webapp 转换为使用 SAML2 身份验证
使用 Node.js 和 SPA 进行 SAML2.0 身份验证