我正在尝试将 Spring Security SAML 扩展 与 Spring Boot 集成。
关于这个问题,我已经开发了一个完整的示例应用程序。其源代码可以在 GitHub 上获取:
通过将其作为 Spring Boot 应用程序运行(运行在内置应用服务器上),WebApp 可以正常工作。
不幸的是,同样的认证流程在 Undertow/WildFly 上根本不能工作。
根据日志,IdP 实际执行了 AuthN 流程:我的自定义 UserDetails
实现的指令被正确执行。尽管执行流程正确,但 Spring 并没有设置和持久化当前用户的权限。
@Component
public class SAMLUserDetailsServiceImpl implements SAMLUserDetailsService {
// Logger
private static final Logger LOG = LoggerFactory.getLogger(SAMLUserDetailsServiceImpl.class);
@Override
public Object loadUserBySAML(SAMLCredential credential)
throws UsernameNotFoundException, SSOUserAccountNotExistsException {
String userID = credential.getNameID().getValue();
if (userID.compareTo("jdoe@samplemail.com") != 0) { // We're simulating the data access.
LOG.warn("SSO User Account not found into the system");
throw new SSOUserAccountNotExistsException("SSO User Account not found into the system", userID);
}
LOG.info(userID + " is logged in");
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
authorities.add(authority);
ExtUser userDetails = new ExtUser(userID, "password", true, true, true,
true, authorities, "John", "Doe");
return userDetails;
}
}
调试过程中,我发现问题出在 FilterChainProxy
类上。运行时,ServletRequest
的属性 FILTER_APPLIED
为 null,因此 Spring 清除了 SecurityContextHolder
。
private final static String FILTER_APPLIED = FilterChainProxy.class.getName().concat(".APPLIED");
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if (clearContext) {
try {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
doFilterInternal(request, response, chain);
} finally {
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
} else {
doFilterInternal(request, response, chain);
}
}
在 VMware vFabric tc Sever 和 Tomcat 上,一切都运行得非常好。你有任何解决此问题的想法吗?
SecurityContextHolder
。该代码的唯一目的是在同一请求中应用过滤器链超过一次的情况下(在这种情况下,只有原始链应该清除上下文)。因此,我认为这不是一个问题。 - Shaun the SheepSecurityContextHolder.clearContext()
并不清除会话数据,它只是在将线程放回线程池之前清除上下文的ThreadLocal
存储。我的观点是,这应该始终发生在请求结束时,所以你看到的情况是正常的,不太可能是问题的原因。 - Shaun the Sheep