Kerberos:协商 Header 无效(原因 GSSException:未提供有效凭据(机制级别:无法找到任何 Kerberos 凭据))
Kerberos: Negotiate Header was invalid (Cause GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos credentails))
呜呜呜!
我尝试使用 Spring Security 5 和 Kerberos 通过 SSO 对用户进行身份验证,但由于 Kerberos 代码深处的异常而失败。我将首先显示堆栈跟踪和导致它的代码,然后提供有关我的环境的其他信息,这可能有助于消除某些可能性。
堆栈跟踪
WARN 3932 --- [apr-8080-exec-1] w.a.SpnegoAuthenticationProcessingFilter : Negotiate Header was invalid: Negotiate YIILSwYGKwYBBQUCoIILPzCCCzugMDAuBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCN[and so on]
org.springframework.security.authentication.BadCredentialsException: Kerberos validation not successful
at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:71) ~[spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
at org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider.authenticate(KerberosServiceAuthenticationProvider.java:64) ~[spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[spring-security-core-5.1.1.RELEASE.jar:5.1.1.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199) ~[spring-security-core-5.1.1.RELEASE.jar:5.1.1.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:512) ~[spring-security-config-5.1.1.RELEASE.jar:5.1.1.RELEASE]
...
Caused by: java.security.PrivilegedActionException: null
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_162]
at javax.security.auth.Subject.doAs(Subject.java:422) ~[na:1.8.0_162]
at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:68) ~[spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
...
Caused by: org.ietf.jgss.GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos credentails)
at sun.security.jgss.krb5.Krb5AcceptCredential.getInstance(Krb5AcceptCredential.java:87) ~[na:1.8.0_162]
at sun.security.jgss.krb5.Krb5MechFactory.getCredentialElement(Krb5MechFactory.java:127) ~[na:1.8.0_162]
at sun.security.jgss.krb5.Krb5MechFactory.getMechanismContext(Krb5MechFactory.java:198) ~[na:1.8.0_162]
所以有一个 BadCredentialsException
而我的 SunJaasKerberosTicketValidator
正在验证 SSO 票证。这只是重新抛出来自
的 PrivilegedActionException
public KerberosTicketValidation validateTicket(byte[] token) {
try {
return Subject.doAs(this.serviceSubject, new KerberosValidateAction(token));
}
catch (PrivilegedActionException e) {
throw new BadCredentialsException("Kerberos validation not successful", e);
}
}
PrivilegedActionException
很难追踪,因为它来自 native
方法 java.security.AccessController.doPrivileged
。我不知道实施。 我觉得有趣的是 PrivilegedActionException
打印出来是
Caused by: java.security.PrivilegedActionException: null
PrivilegedActionException.toString
方法是
public String toString() {
String s = getClass().getName();
return (exception != null) ? (s + ": " + exception.toString()) : s;
}
所以 exception
(原因异常)不为空,但打印为 null
...
但是堆栈跟踪告诉我们 问题的根源 是 GSSException
来自 class Krb5AcceptCredential.
if (creds == null)
throw new GSSException(GSSException.NO_CRED, -1,"Failed to find any Kerberos credentails");
而creds == null
是因为Krb5Util.getServiceCreds
(见implementation)returnsnull
没有引起异常
这是我到目前为止的进展。现在一些额外的信息。
在我的 WebSecurityConfig 中创建票证验证器
SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
ticketValidator.setServicePrincipal("HTTP/host@REALM");
FileSystemResource fs = new FileSystemResource("PATH_TO_KEYTAB");
ticketValidator.setKeyTabLocation(fs);
LOGGER.info(fs.exists()); // prints 'true'
创建 KerberosServiceAuthenticationProvider
这是 object 的配置,它将抛出 BadCredentialsException
。
KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
provider.setTicketValidator(sunJaasKerberosTicketValidator());
provider.setUserDetailsService(myUserDetailService);
provider.supports(KerberosServiceRequestToken.class);
我知道 SSO 有效
我有幸能够证明我公司的 SSO 基础设施有效。同一台服务器是 运行 另一个应用程序(Spring Security 4 with Kerberos),用户可以在其中通过 SSO 成功进行身份验证。所以我的设置很可能有问题。
我顺便用了Chrome,不过我也用IE测试过
如果您需要我的 WebSecurityConfig
或其他方面的更多信息,我会提供。愿原力与你同在:-)
其他问题
这是我目前的发现,但这些示例略有不同。
- GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)
- 其他错误信息
- 其他设置:我没有 krb5.conf 文件
- BadCredentialsException: Kerberos validation not succesfull
- 导致
BadCredentialsException
的其他根异常
- 从 2012 年开始
- Kerberos authentication not working with spring security
- 导致
BadCredentialsException
的其他根异常
我遇到那个问题已经 2 年了,但我记得,我解决了它……忘记了 post 这里的解决方案(我的错)。由于这个问题得到了一些新的关注,我会尽力记住。
我找出了代码,我想我记得这个问题。在 WebSecurityConfig 中,有一些方法被注释为 @Bean
- 并且缺少一个。
我认为是 SunJaasKerberosTicketValidator
。它在此 class 中用于配置 KerberosServiceAuthenticationProvider
,但 Spring 安全性似乎也在内部使用该 Bean - 如果 Spring 上下文中缺少该 bean,则会失败。
这是我当时的代码的(简化)版本。检查所有用 @Bean
注释的方法,如果你也有的话。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
auth.authenticationProvider(kerberosServiceAuthenticationProvider());
}
@Override
public void configure(WebSecurity web) {
// ...
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//...
}
@Bean
public SpnegoEntryPoint spnegoEntryPoint() {
//...
}
private KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
provider.setTicketValidator(ticketValidator());
provider.setUserDetailsService(myUserDetailsService);
return provider;
}
@Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter() {
SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
AuthenticationFailureHandler failureHandler =
new SimpleUrlAuthenticationFailureHandler(AUTHENTIFICATION_FAILED_URL);
filter.setFailureHandler(failureHandler);
try {
filter.setAuthenticationManager(authenticationManagerBean());
} catch (Exception e) {
throw new IllegalStateException(e);
}
return filter;
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public SunJaasKerberosTicketValidator ticketValidator() {
SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
ticketValidator.setDebug(true);
ticketValidator.setServicePrincipal(kerberosConfigMgmt.securityKerberosServicePrincipal());
FileSystemResource fs = new FileSystemResource(kerberosConfigMgmt.securityKerberosKeyTapFileAbsolutePath());
ticketValidator.setKeyTabLocation(fs);
return ticketValidator;
}
@Bean(name = "authenticationSuccessHandler")
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return new SimpleUrlAuthenticationSuccessHandler(STARTSEITE_URL);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
呜呜呜!
我尝试使用 Spring Security 5 和 Kerberos 通过 SSO 对用户进行身份验证,但由于 Kerberos 代码深处的异常而失败。我将首先显示堆栈跟踪和导致它的代码,然后提供有关我的环境的其他信息,这可能有助于消除某些可能性。
堆栈跟踪
WARN 3932 --- [apr-8080-exec-1] w.a.SpnegoAuthenticationProcessingFilter : Negotiate Header was invalid: Negotiate YIILSwYGKwYBBQUCoIILPzCCCzugMDAuBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCN[and so on]
org.springframework.security.authentication.BadCredentialsException: Kerberos validation not successful
at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:71) ~[spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
at org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider.authenticate(KerberosServiceAuthenticationProvider.java:64) ~[spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[spring-security-core-5.1.1.RELEASE.jar:5.1.1.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199) ~[spring-security-core-5.1.1.RELEASE.jar:5.1.1.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:512) ~[spring-security-config-5.1.1.RELEASE.jar:5.1.1.RELEASE]
...
Caused by: java.security.PrivilegedActionException: null
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_162]
at javax.security.auth.Subject.doAs(Subject.java:422) ~[na:1.8.0_162]
at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:68) ~[spring-security-kerberos-core-1.0.1.RELEASE.jar:1.0.1.RELEASE]
...
Caused by: org.ietf.jgss.GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos credentails)
at sun.security.jgss.krb5.Krb5AcceptCredential.getInstance(Krb5AcceptCredential.java:87) ~[na:1.8.0_162]
at sun.security.jgss.krb5.Krb5MechFactory.getCredentialElement(Krb5MechFactory.java:127) ~[na:1.8.0_162]
at sun.security.jgss.krb5.Krb5MechFactory.getMechanismContext(Krb5MechFactory.java:198) ~[na:1.8.0_162]
所以有一个
的BadCredentialsException
而我的SunJaasKerberosTicketValidator
正在验证 SSO 票证。这只是重新抛出来自PrivilegedActionException
public KerberosTicketValidation validateTicket(byte[] token) { try { return Subject.doAs(this.serviceSubject, new KerberosValidateAction(token)); } catch (PrivilegedActionException e) { throw new BadCredentialsException("Kerberos validation not successful", e); }
}
PrivilegedActionException
很难追踪,因为它来自native
方法java.security.AccessController.doPrivileged
。我不知道实施。 我觉得有趣的是PrivilegedActionException
打印出来是Caused by: java.security.PrivilegedActionException: null
PrivilegedActionException.toString
方法是public String toString() { String s = getClass().getName(); return (exception != null) ? (s + ": " + exception.toString()) : s; }
所以
exception
(原因异常)不为空,但打印为null
...但是堆栈跟踪告诉我们 问题的根源 是
GSSException
来自 class Krb5AcceptCredential.if (creds == null) throw new GSSException(GSSException.NO_CRED, -1,"Failed to find any Kerberos credentails");
而
creds == null
是因为Krb5Util.getServiceCreds
(见implementation)returnsnull
没有引起异常
这是我到目前为止的进展。现在一些额外的信息。
在我的 WebSecurityConfig 中创建票证验证器
SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
ticketValidator.setServicePrincipal("HTTP/host@REALM");
FileSystemResource fs = new FileSystemResource("PATH_TO_KEYTAB");
ticketValidator.setKeyTabLocation(fs);
LOGGER.info(fs.exists()); // prints 'true'
创建 KerberosServiceAuthenticationProvider
这是 object 的配置,它将抛出 BadCredentialsException
。
KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
provider.setTicketValidator(sunJaasKerberosTicketValidator());
provider.setUserDetailsService(myUserDetailService);
provider.supports(KerberosServiceRequestToken.class);
我知道 SSO 有效
我有幸能够证明我公司的 SSO 基础设施有效。同一台服务器是 运行 另一个应用程序(Spring Security 4 with Kerberos),用户可以在其中通过 SSO 成功进行身份验证。所以我的设置很可能有问题。
我顺便用了Chrome,不过我也用IE测试过
如果您需要我的 WebSecurityConfig
或其他方面的更多信息,我会提供。愿原力与你同在:-)
其他问题
这是我目前的发现,但这些示例略有不同。
- GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)
- 其他错误信息
- 其他设置:我没有 krb5.conf 文件
- BadCredentialsException: Kerberos validation not succesfull
- 导致
BadCredentialsException
的其他根异常
- 从 2012 年开始
- 导致
- Kerberos authentication not working with spring security
- 导致
BadCredentialsException
的其他根异常
- 导致
我遇到那个问题已经 2 年了,但我记得,我解决了它……忘记了 post 这里的解决方案(我的错)。由于这个问题得到了一些新的关注,我会尽力记住。
我找出了代码,我想我记得这个问题。在 WebSecurityConfig 中,有一些方法被注释为 @Bean
- 并且缺少一个。
我认为是 SunJaasKerberosTicketValidator
。它在此 class 中用于配置 KerberosServiceAuthenticationProvider
,但 Spring 安全性似乎也在内部使用该 Bean - 如果 Spring 上下文中缺少该 bean,则会失败。
这是我当时的代码的(简化)版本。检查所有用 @Bean
注释的方法,如果你也有的话。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
auth.authenticationProvider(kerberosServiceAuthenticationProvider());
}
@Override
public void configure(WebSecurity web) {
// ...
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//...
}
@Bean
public SpnegoEntryPoint spnegoEntryPoint() {
//...
}
private KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
provider.setTicketValidator(ticketValidator());
provider.setUserDetailsService(myUserDetailsService);
return provider;
}
@Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter() {
SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
AuthenticationFailureHandler failureHandler =
new SimpleUrlAuthenticationFailureHandler(AUTHENTIFICATION_FAILED_URL);
filter.setFailureHandler(failureHandler);
try {
filter.setAuthenticationManager(authenticationManagerBean());
} catch (Exception e) {
throw new IllegalStateException(e);
}
return filter;
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public SunJaasKerberosTicketValidator ticketValidator() {
SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
ticketValidator.setDebug(true);
ticketValidator.setServicePrincipal(kerberosConfigMgmt.securityKerberosServicePrincipal());
FileSystemResource fs = new FileSystemResource(kerberosConfigMgmt.securityKerberosKeyTapFileAbsolutePath());
ticketValidator.setKeyTabLocation(fs);
return ticketValidator;
}
@Bean(name = "authenticationSuccessHandler")
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return new SimpleUrlAuthenticationSuccessHandler(STARTSEITE_URL);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}