此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Security Kerberos 2.1.0spring-doc.cn

Spring 和 Spring Security Kerberos

参考文档的这一部分介绍了核心功能 Spring Security Kerberos 提供给任何基于 Spring 的应用程序。spring-doc.cn

身份验证提供程序 描述身份验证提供程序支持。spring-doc.cn

Spnego Negotiate 介绍了 spnego 协商支持。spring-doc.cn

使用 KerberosRestTemplate 介绍了 RestTemplate 支持。spring-doc.cn

身份验证提供程序

使用 JavaConfig 的提供程序配置。spring-doc.cn

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Value("${app.service-principal}")
	private String servicePrincipal;

	@Value("${app.keytab-location}")
	private String keytabLocation;

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		KerberosAuthenticationProvider kerberosAuthenticationProvider = kerberosAuthenticationProvider();
		KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider = kerberosServiceAuthenticationProvider();
		ProviderManager providerManager = new ProviderManager(kerberosAuthenticationProvider,
				kerberosServiceAuthenticationProvider);

		http
			.authorizeHttpRequests((authz) -> authz
				.requestMatchers("/", "/home").permitAll()
				.anyRequest().authenticated()
			)
			.exceptionHandling()
				.authenticationEntryPoint(spnegoEntryPoint())
				.and()
			.formLogin()
				.loginPage("/login").permitAll()
				.and()
			.logout()
				.permitAll()
				.and()
			.authenticationProvider(kerberosAuthenticationProvider())
			.authenticationProvider(kerberosServiceAuthenticationProvider())
			.addFilterBefore(spnegoAuthenticationProcessingFilter(providerManager),
					BasicAuthenticationFilter.class);
			return http.build();
	}

	@Bean
	public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
		KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider();
		SunJaasKerberosClient client = new SunJaasKerberosClient();
		client.setDebug(true);
		provider.setKerberosClient(client);
		provider.setUserDetailsService(dummyUserDetailsService());
		return provider;
	}

	@Bean
	public SpnegoEntryPoint spnegoEntryPoint() {
		return new SpnegoEntryPoint("/login");
	}

	public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
			AuthenticationManager authenticationManager) {
		SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
		filter.setAuthenticationManager(authenticationManager);
		return filter;
	}

	@Bean
	public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
		KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
		provider.setTicketValidator(sunJaasKerberosTicketValidator());
		provider.setUserDetailsService(dummyUserDetailsService());
		return provider;
	}

	@Bean
	public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
		SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
		ticketValidator.setServicePrincipal(servicePrincipal);
		ticketValidator.setKeyTabLocation(new FileSystemResource(keytabLocation));
		ticketValidator.setDebug(true);
		return ticketValidator;
	}

	@Bean
	public DummyUserDetailsService dummyUserDetailsService() {
		return new DummyUserDetailsService();
	}
}

Spnego 协商

使用 JavaConfig 的 Spnego 配置。spring-doc.cn

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Value("${app.ad-domain}")
	private String adDomain;

	@Value("${app.ad-server}")
	private String adServer;

	@Value("${app.service-principal}")
	private String servicePrincipal;

	@Value("${app.keytab-location}")
	private String keytabLocation;

	@Value("${app.ldap-search-base}")
	private String ldapSearchBase;

	@Value("${app.ldap-search-filter}")
	private String ldapSearchFilter;

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider = kerberosServiceAuthenticationProvider();
		ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider = activeDirectoryLdapAuthenticationProvider();
		ProviderManager providerManager = new ProviderManager(kerberosServiceAuthenticationProvider,
				activeDirectoryLdapAuthenticationProvider);

		http
			.authorizeHttpRequests((authz) -> authz
				.requestMatchers("/", "/home").permitAll()
				.anyRequest().authenticated()
			)
			.exceptionHandling()
				.authenticationEntryPoint(spnegoEntryPoint())
				.and()
			.formLogin()
				.loginPage("/login").permitAll()
				.and()
			.logout()
				.permitAll()
				.and()
			.authenticationProvider(activeDirectoryLdapAuthenticationProvider())
			.authenticationProvider(kerberosServiceAuthenticationProvider())
			.addFilterBefore(spnegoAuthenticationProcessingFilter(providerManager),
				BasicAuthenticationFilter.class);

		return http.build();
	}

	@Bean
	public ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
		return new ActiveDirectoryLdapAuthenticationProvider(adDomain, adServer);
	}

	@Bean
	public SpnegoEntryPoint spnegoEntryPoint() {
		return new SpnegoEntryPoint("/login");
	}

	public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
			AuthenticationManager authenticationManager) {
		SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
		filter.setAuthenticationManager(authenticationManager);
		return filter;
	}

	public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() throws Exception {
		KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
		provider.setTicketValidator(sunJaasKerberosTicketValidator());
		provider.setUserDetailsService(ldapUserDetailsService());
		return provider;
	}

	@Bean
	public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
		SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
		ticketValidator.setServicePrincipal(servicePrincipal);
		ticketValidator.setKeyTabLocation(new FileSystemResource(keytabLocation));
		ticketValidator.setDebug(true);
		return ticketValidator;
	}

	@Bean
	public KerberosLdapContextSource kerberosLdapContextSource() throws Exception {
		KerberosLdapContextSource contextSource = new KerberosLdapContextSource(adServer);
		contextSource.setLoginConfig(loginConfig());
		return contextSource;
	}

	public SunJaasKrb5LoginConfig loginConfig() throws Exception {
		SunJaasKrb5LoginConfig loginConfig = new SunJaasKrb5LoginConfig();
		loginConfig.setKeyTabLocation(new FileSystemResource(keytabLocation));
		loginConfig.setServicePrincipal(servicePrincipal);
		loginConfig.setDebug(true);
		loginConfig.setIsInitiator(true);
		loginConfig.afterPropertiesSet();
		return loginConfig;
	}

	@Bean
	public LdapUserDetailsService ldapUserDetailsService() throws Exception {
		FilterBasedLdapUserSearch userSearch =
				new FilterBasedLdapUserSearch(ldapSearchBase, ldapSearchFilter, kerberosLdapContextSource());
		LdapUserDetailsService service =
				new LdapUserDetailsService(userSearch, new ActiveDirectoryLdapAuthoritiesPopulator());
		service.setUserDetailsMapper(new LdapUserDetailsMapper());
		return service;
	}
}

使用 KerberosRestTemplate

如果需要访问受 Kerberos 保护的 Web 资源 从编程方式上,我们有 which extends 并在委托给 实际的 RestTemplate 方法。您基本上几乎没有选择 配置此模板。KerberosRestTemplateRestTemplatespring-doc.cn

  • 如果需要,请将 keyTabLocation 和 userPrincipal 留空 使用缓存的票证。spring-doc.cn

  • 如果要使用 keyTabLocation 和 userPrincipal keytab 文件。spring-doc.cn

  • 如果要自定义 Krb5LoginModule 选项,请使用 loginOptions。spring-doc.cn

  • 使用自定义的 httpClient。spring-doc.cn

带ticket缓存。spring-doc.cn

public void doWithTicketCache() {
    KerberosRestTemplate restTemplate =
            new KerberosRestTemplate();
    restTemplate.getForObject("http://neo.example.org:8080/hello", String.class);
}

使用 keytab 文件。spring-doc.cn

public void doWithKeytabFile() {
    KerberosRestTemplate restTemplate =
            new KerberosRestTemplate("/tmp/user2.keytab", "[email protected]");
    restTemplate.getForObject("http://neo.example.org:8080/hello", String.class);
}

使用 LDAP 服务进行身份验证

对于您的大多数示例,我们使用的是因为不一定需要查询真实用户详细信息 一旦 Kerberos 身份验证成功,我们就可以使用 Kerberos principal 信息来创建该虚拟用户。但是,有一种方法可以 以 say 方式访问基于 Kerberos 的 LDAP 服务并查询用户详细信息 从那里开始。DummyUserDetailsServicespring-doc.cn

KerberosLdapContextSource可用于通过 Kerberos 绑定到 LDAP 至少证明它与 Windows AD 服务配合得很好。spring-doc.cn

@Value("${app.ad-server}")
private String adServer;

@Value("${app.service-principal}")
private String servicePrincipal;

@Value("${app.keytab-location}")
private String keytabLocation;

@Value("${app.ldap-search-base}")
private String ldapSearchBase;

@Value("${app.ldap-search-filter}")
private String ldapSearchFilter;

@Bean
public KerberosLdapContextSource kerberosLdapContextSource() {
	KerberosLdapContextSource contextSource = new KerberosLdapContextSource(adServer);
	SunJaasKrb5LoginConfig loginConfig = new SunJaasKrb5LoginConfig();
	loginConfig.setKeyTabLocation(new FileSystemResource(keytabLocation));
	loginConfig.setServicePrincipal(servicePrincipal);
	loginConfig.setDebug(true);
	loginConfig.setIsInitiator(true);
	contextSource.setLoginConfig(loginConfig);
	return contextSource;
}

@Bean
public LdapUserDetailsService ldapUserDetailsService() {
	FilterBasedLdapUserSearch userSearch =
			new FilterBasedLdapUserSearch(ldapSearchBase, ldapSearchFilter, kerberosLdapContextSource());
	LdapUserDetailsService service = new LdapUserDetailsService(userSearch);
	service.setUserDetailsMapper(new LdapUserDetailsMapper());
	return service;
}

Security Server Windows 身份验证示例当前配置为在通过 Kerberos 进行身份验证时从 AD 查询用户详细信息。spring-doc.cn