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

hjqgdpho  于 2023-01-13  发布在  Spring
关注(0)|答案(1)|浏览(344)

在springsecuritysaml2provider版本5.7.x中,如果在身份验证响应中提供了InResponseTo,则引入了InResponseTo的强制验证。
验证逻辑期望在HttpSession中找到保存的Saml2AuthenticationRequest。但是,只有在未设置SameSite属性的情况下才可能找到。
根据当前项目的安全要求,我正在将其设置为宽松或严格。此配置是在应用程序外部完成的。这会导致会话和请求数据丢失。
也许有人已经处理了一个问题,并知道如何处理它?我没有看到任何方法来禁用验证或保存请求的替代方法在库中可用。

nxagd54h

nxagd54h1#

在将spring security从5.x升级到6时,我遇到了spring session 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请求之间更改,因此这似乎是合理的替代方案(目前尚无任何标准解决方案)。我正在通过标准安全测试运行此内容,并将使用我的发现(如果有)更新解决方案。

相关问题