3

我希望有人能给我一个比我在文档中找到的更具体的例子。

使用 SpringBoot/Spring Security 5.6.0。我正在将基于 SpringSecurity/SAML 的身份验证过程迁移到SAML2

我需要将根据 responseToken 信息构建的 UserDetails 添加到身份验证中。类似于我们可以在文档中阅读的内容:https ://docs.spring.io/spring-security/reference/5.6.0-RC1/servlet/saml2/index.html#servlet-saml2login-opensamlauthenticationprovider-userdetailsservice

但我不明白第三点:返回包含用户详细信息的自定义身份验证:“return MySaml2Authentication(userDetails, authentication);”

在任何情况下,您都必须执行“return new MySaml2Authentication(userDetails, authentication);” 正确的?

在任何情况下,当进程继续时,它会被执行:

身份验证 authenticate = provider.authenticate(authentication);

正如我们所见,它将 Details 值替换为原始值。

authenticationResponse.setDetails(authentication.getDetails());

/**
 * @param authentication the authentication request object, must be of type
 * {@link Saml2AuthenticationToken}
 * @return {@link Saml2Authentication} if the assertion is valid
 * @throws AuthenticationException if a validation exception occurs
 */
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    try {
        Saml2AuthenticationToken token = (Saml2AuthenticationToken) authentication;
        String serializedResponse = token.getSaml2Response();
        Response response = parse(serializedResponse);
        process(token, response);
        AbstractAuthenticationToken authenticationResponse = this.responseAuthenticationConverter
                .convert(new ResponseToken(response, token));
        if (authenticationResponse != null) {
            authenticationResponse.setDetails(authentication.getDetails());
        }
        return authenticationResponse;
    }
    catch (Saml2AuthenticationException ex) {
        throw ex;
    }
    catch (Exception ex) {
        throw createAuthenticationException(Saml2ErrorCodes.INTERNAL_VALIDATION_ERROR, ex.getMessage(), ex);
    }
}

如何添加一个依赖于从令牌获得的信息的 UserDetails?我不能扩展 OpenSaml4AuthenticationProvider 因为它是"final"

我唯一能想到的是选项:https ://docs.spring.io/spring-security/reference/5.6.0-RC1/servlet/saml2/index.html#servlet-saml2login-authenticationmanager-custom

并在 MySaml2AuthenticationManager 中设置 Details 后执行Authentication authenticate = provider.authenticate(authentication); 但这对我来说似乎不对。

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    OpenSaml4AuthenticationProvider provider = new OpenSaml4AuthenticationProvider();

    provider.setResponseAuthenticationConverter(responseToken -> {

        Saml2Authentication auth = OpenSaml4AuthenticationProvider
                .createDefaultResponseAuthenticationConverter()// First, call the default converter, which extracts attributes and authorities from the response
                .convert(responseToken);

        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        String role = getRole(auth.getName());
        grantedAuthorities.add(new SimpleGrantedAuthority(role));


        Saml2Authentication saml2Authentication = new Saml2Authentication((AuthenticatedPrincipal) auth.getPrincipal(), auth.getSaml2Response(), grantedAuthorities);
        
        /*
        //The details are replaced by the authentication.getDetails().
        MyUserDetails userDetails = new MyUserDetails(authenticate.getName(),auth.getPrincipal());
        saml2Authentication.setDetails(userDetails);
        */
        return saml2Authentication;
    });

    Authentication authenticate = provider.authenticate(authentication);

    //Doesn't sound like a good idea
    if ((authenticate.getPrincipal() instanceof DefaultSaml2AuthenticatedPrincipal)) {
        DefaultSaml2AuthenticatedPrincipal samlPrincipal = (DefaultSaml2AuthenticatedPrincipal) authenticate.getPrincipal();
        MyUserDetails userDetails = new MyUserDetails(authenticate.getName(),
                samlPrincipal.getFirstAttribute("SMFIRSTNAME")
                , samlPrincipal.getFirstAttribute("SMLASTNAME")
                , samlPrincipal.getFirstAttribute("SMEMAIL"));
        ((Saml2Authentication)authenticate).setDetails(defaultDISUserDetails);
    }
    return authenticate;

有更好的选择吗?

非常感谢您的帮助

此致

4

1 回答 1

1

我也发现这个太晚了。但是您实际上应该使用自己的 AbstractAuthenticationToken 实现并使用一个额外的字段来填充您自己的对象。这是我的:

public class CustomSaml2Authentication extends Saml2Authentication {

private User user;

public CustomSaml2Authentication(AuthenticatedPrincipal principal, String saml2Response,
        Collection<? extends GrantedAuthority> authorities) {
    super(principal, saml2Response, authorities);
}

public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}

}
于 2022-01-25T13:19:24.593 回答