Spring security saml2 提供程序:即使未找到保存的请求,也会执行对 saml2 的 InResponseTo 验证

问题描述 投票:0回答:2

在 Spring Security saml2 提供程序版本 5.7.x 中,如果在身份验证响应中提供了 InResponseTo,则引入了强制验证。

验证逻辑期望在 HttpSession 中找到保存的 Saml2AuthenticationRequest。然而,只有在未设置 SameSite 属性的情况下,这才有可能。

根据我当前项目的安全要求,将其设置为宽松或严格。此配置是在应用程序外部完成的。这会导致会话和请求数据丢失。

也许有人已经处理过某个问题并且知道如何处理?我没有看到任何禁用验证的方法或保存库中可用的请求的替代方法。

spring-security saml-2.0
2个回答
5
投票

在将 Spring Security 从 5.x 升级到 6 时,我遇到了 Spring 会话 cookie 的相同问题。对此似乎没有任何标准解决方案。目前,我提供了

Saml2AuthenticationRequestRepository
的实现,它根据 RelayState 参数将 SAML 请求保存在数据库中。以下是使用 Mongo 的示例实现。任何后端(内存缓存、Redis、MySQL 等)都可以使用 -

import java.util.Optional;

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.security.saml2.core.Saml2ParameterNames;
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
import org.springframework.stereotype.Repository;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Repository
@RequiredArgsConstructor
@Slf4j
public class MongoSaml2AuthenticationRequestRepository implements Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> {

    public static final String SAML2_REQUEST_COLLECTION = "saml2RequestsRepository";
    private final @NonNull MongoTemplate mongoTemplate;
    
    @Override
    public AbstractSaml2AuthenticationRequest loadAuthenticationRequest(HttpServletRequest request) {
        
        String relayState = request.getParameter(Saml2ParameterNames.RELAY_STATE);
        if (relayState == null) {
            return null;
        }
        
        log.debug("Fetching SAML2 Authentication Request by relay state : {}", relayState.get());
        Query query = Query.query(Criteria.where("relayState").is(relayState.get()));
        AbstractSaml2AuthenticationRequest authenticationRequest = mongoTemplate.findOne(query, AbstractSaml2AuthenticationRequest.class, SAML2_REQUEST_COLLECTION);
        
        if (!authenticationRequest.getRelayState().equals(relayState.get())) {
            log.error("Relay State received from request '{}' is different from saved request '{}'.", relayState.get(), authenticationRequest.getRelayState());
            return null;
        }
        
        log.debug("SAML2 Request retrieved : {}", authenticationRequest);
        return authenticationRequest;
    }

    @Override
    public void saveAuthenticationRequest(AbstractSaml2AuthenticationRequest authenticationRequest,
            HttpServletRequest request, HttpServletResponse response) {
        
        //As per OpenSamlAuthenticationRequestResolver, it will always have value. However, one validation can be added to check for null and regenerate.
        String relayState = authenticationRequest.getRelayState();
        log.debug("Relay State Received: {}", relayState);
        mongoTemplate.save(authenticationRequest, SAML2_REQUEST_COLLECTION);
    }

    @Override
    public AbstractSaml2AuthenticationRequest removeAuthenticationRequest(HttpServletRequest request,
            HttpServletResponse response) {
        
        AbstractSaml2AuthenticationRequest authenticationRequest = loadAuthenticationRequest(request);
        if (authenticationRequest == null) {
            return null;
        }
        
        mongoTemplate.remove(authenticationRequest, SAML2_REQUEST_COLLECTION);
        return authenticationRequest;
    }

}

添加此后,所有 SAML 验证(包括 InResponseTo 验证)均已成功通过。由于 RelayState 不应该根据规范在 SAML 请求之间更改,因此这似乎是合理的替代方案(到目前为止还没有任何标准解决方案)。我正在通过标准安全测试来运行它,并将用我的发现更新解决方案(如果有)。


0
投票

我有同样的问题,我尝试了一些方法,例如设置 sameSite=None,但它不起作用

© www.soinside.com 2019 - 2024. All rights reserved.