Kerberos: недопустимый заголовок согласования (причина GSSException: не предоставлены действительные учетные данные (уровень механизма: не удалось найти какие-либо учетные данные Kerberos))

Мойн!

Мои попытки аутентифицировать пользователя через SSO с Spring Security 5 и Kerberos терпят неудачу из-за исключения из глубины кода 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]
  1. Итак, есть 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);
    }
    

    }

  2. 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...

  3. Однако трассировка стека говорит нам, что корень проблемы — это GSSException, происходящее из класса Krb5AcceptCredential.

    if (creds == null)
        throw new GSSException(GSSException.NO_CRED, -1,"Failed to find any Kerberos credentails");
    

    А creds == null потому, что Krb5Util.getServiceCreds (см. реализация) возвращает null, не вызывая исключения.

Вот как далеко я продвинулся до сих пор. Теперь немного дополнительной информации.

Создание валидатора билетов в моем 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

Это конфигурация объекта, который будет выбрасывать BadCredentialsException.

    KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
    provider.setTicketValidator(sunJaasKerberosTicketValidator());
    provider.setUserDetailsService(myUserDetailService);
    provider.supports(KerberosServiceRequestToken.class);

Я знаю, что система единого входа работает

Я могу позволить себе роскошь доказать, что инфраструктура SSO моей компании работает. На том же сервере запущено другое приложение (Spring Security 4 с Kerberos), в котором пользователь может быть успешно аутентифицирован через SSO. Так что, скорее всего, что-то не так с моей настройкой.

Кстати, я использую Chrome, но я также тестировал его с IE.

Если вам нужна дополнительная информация из моего WebSecurityConfig или что-то еще, я предоставлю ее. Да прибудет с тобой сила :-)

Другие вопросы

Это то, что я нашел до сих пор, но эти примеры немного отличаются.

Все еще не знаете, как решить эту проблему?

Klapsa2503 15.06.2021 16:30

@ Klapsa2503 Klapsa2503 - если у вас возникла та же проблема, очень полезно предоставить сведения о HTTP-запросе и ответе (включая заголовки и т. д. - эквивалент curl -v). Эти проблемы обычно возникают из-за того, что клиент не отправляет билет Curb в первую очередь по запросу. Иногда он возвращается к NTLM или просто не добавляет билет. В любом случае это невозможно узнать без контекста запроса

stringy05 17.06.2021 04:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
2
2 038
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Прошло 2 года с тех пор, как у меня была эта проблема, но я помню, что решил ее... и забыл опубликовать решение здесь (мое плохое). Поскольку вопрос привлек новое внимание, я постараюсь запомнить его.

Я выкопал код и, кажется, вспомнил проблему. В WebSecurityConfig есть несколько методов, помеченных как @Bean, и один из них отсутствует. Я думаю, что это был SunJaasKerberosTicketValidator. Он используется в этом классе для настройки KerberosServiceAuthenticationProvider, но Spring Security, похоже, также использует этот Bean внутри — и терпит неудачу, если bean-компонент отсутствует в контексте Spring.

Вот (сокращенная) версия моего кода того времени. Проверьте все методы, отмеченные @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();
    }

}

Другие вопросы по теме