You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security Kerberos 2.0中如何从SpnegoAuthenticationToken获取PAC SIDs?

解决方案与版本支持说明

一、Spring Security Kerberos 2.0 可行实现方案

你可以通过自定义AuthenticationProvider绕过KerberosServiceAuthenticationProvider的限制,直接从SpnegoAuthenticationToken中提取PAC SIDs,具体实现如下:

1. 自定义认证提供者

实现AuthenticationProvider接口,专门处理SpnegoAuthenticationToken并解析PAC获取SIDs:

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.kerberos.authentication.SpnegoAuthenticationToken;
import org.springframework.security.kerberos.authentication.KerberosTicket;
import sun.security.krb5.internal.Ticket;

import java.io.ByteArrayInputStream;
import java.util.Base64;

public class SpnegoPacAuthenticationProvider implements AuthenticationProvider {

    private final UserDetailsService userDetailsService;

    public SpnegoPacAuthenticationProvider(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return SpnegoAuthenticationToken.class.isAssignableFrom(authentication);
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SpnegoAuthenticationToken token = (SpnegoAuthenticationToken) authentication;
        KerberosTicket kerberosTicket = token.getTicket();
        
        // 从Kerberos Ticket中提取并解析PAC SIDs
        String pacSids = extractPacSids(kerberosTicket);
        
        // 加载基础用户信息
        UserDetails userDetails = userDetailsService.loadUserByUsername(token.getName());
        
        // 将PAC SIDs注入自定义UserDetails对象(需提前实现带SIDs字段的UserDetails)
        if (userDetails instanceof CustomUserDetails customUser) {
            customUser.setPacSids(pacSids);
        }
        
        // 返回已完成认证的令牌
        return new SpnegoAuthenticationToken(userDetails, userDetails.getAuthorities(), kerberosTicket);
    }

    private String extractPacSids(KerberosTicket kerberosTicket) {
        try {
            byte[] ticketBytes = Base64.getDecoder().decode(kerberosTicket.getEncoded());
            Ticket ticket = new Ticket(new ByteArrayInputStream(ticketBytes));
            // 此处需实现PAC数据的具体解析逻辑,可参考kerb4j的PAC解析代码
            // 示例仅做占位,实际需替换为真实解析逻辑
            return parseSidsFromPacData(ticket.getEncPart().getCipher());
        } catch (Exception e) {
            throw new RuntimeException("Failed to extract PAC SIDs", e);
        }
    }

    private String parseSidsFromPacData(byte[] pacData) {
        // 实现PAC数据解析,提取用户SID和组SID
        return "S-1-5-21-XXX-XXX-XXX-1001,S-1-5-21-XXX-XXX-XXX-513";
    }
}

2. 配置Spring Security认证链

在Security配置中注册自定义Provider,替换默认的Kerberos认证提供者:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final UserDetailsService userDetailsService;

    public SecurityConfig(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .addFilterBefore(spnegoFilter(), SpnegoAuthenticationProcessingFilter.class);
        return http.build();
    }

    @Bean
    public SpnegoAuthenticationProcessingFilter spnegoFilter() throws Exception {
        SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(new SpnegoPacAuthenticationProvider(userDetailsService));
    }
}

注意事项

  • 解析PAC时,JDK内部的sun.security.krb5包类存在版本兼容性风险,建议使用Apache Directory Server的kerberos-codec模块替代,保证解析逻辑稳定。
  • 需自定义UserDetails实现类,添加PAC SIDs的存储字段,方便后续权限判断使用。

二、2.1版本支持情况

目前Spring Security Kerberos官方的2.1版本规划中,暂未明确将支持AuthenticationUserDetailsService传入KerberosServiceAuthenticationProvider的功能列入开发计划。可关注项目的GitHub Issues或Milestone页面,获取功能迭代的最新动态。

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 02:32:48