代码之家  ›  专栏  ›  技术社区  ›  rachelle

Spring security kerberos可用于xml配置,但不能用于Java配置

  •  2
  • rachelle  · 技术社区  · 8 年前

    我在中使用了spring security kerberos的示例 xml config java config . 这是完全相同的配置(一个在xml中,一个在java中)。

    然而,当我使用带有java配置的项目时,我有一个堆栈跟踪:

    org.springframework.security.authentication.BadCredentialsException: Kerberos validation not successful
        at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:71)
        at org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider.authenticate(KerberosServiceAuthenticationProvider.java:64)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
        at org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter.doFilter(SpnegoAuthenticationProcessingFilter.java:145)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:89)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
        at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
    Caused by: java.security.PrivilegedActionException: null
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAs(Subject.java:422)
        at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:68)
        ... 61 common frames omitted
    Caused by: org.ietf.jgss.GSSException: Failure unspecified at GSS-API level (Mechanism level: Invalid argument (400) - Cannot find key of appropriate type to decrypt AP REP - AES256 CTS mode with HMAC SHA1-96)
        at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:856)
        at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342)
        at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
        at sun.security.jgss.spnego.SpNegoContext.GSS_acceptSecContext(SpNegoContext.java:906)
        at sun.security.jgss.spnego.SpNegoContext.acceptSecContext(SpNegoContext.java:556)
        at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342)
        at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285)
        at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:170)
        at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:153)
        ... 64 common frames omitted
    Caused by: sun.security.krb5.KrbException: Invalid argument (400) - Cannot find key of appropriate type to decrypt AP REP - AES256 CTS mode with HMAC SHA1-96
        at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:278)
        at sun.security.krb5.KrbApReq.<init>(KrbApReq.java:149)
        at sun.security.jgss.krb5.InitSecContextToken.<init>(InitSecContextToken.java:108)
        at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:829)
        ... 72 common frames omitted
    

    这里是我的xml配置:

    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:sec="http://www.springframework.org/schema/security"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
    
    <sec:http entry-point-ref="spnegoEntryPoint" use-expressions="true" >
        <sec:intercept-url pattern="/" access="permitAll" />
        <sec:intercept-url pattern="/home" access="permitAll" />
        <sec:intercept-url pattern="/login" access="permitAll" />
        <sec:intercept-url pattern="/**" access="authenticated"/>
        <sec:form-login login-page="/login" />
        <sec:custom-filter ref="spnegoAuthenticationProcessingFilter"
            before="BASIC_AUTH_FILTER" />
    </sec:http>
    
    <sec:authentication-manager alias="authenticationManager">
        <sec:authentication-provider ref="kerberosAuthenticationProvider" />
        <sec:authentication-provider ref="kerberosServiceAuthenticationProvider" />
    </sec:authentication-manager>
    
    <bean id="kerberosAuthenticationProvider"
        class="org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider">
        <property name="userDetailsService" ref="dummyUserDetailsService"/>
        <property name="kerberosClient">
            <bean class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient">
                <property name="debug" value="true"/>
            </bean>
        </property>
    </bean>
    
    <bean id="spnegoEntryPoint"
        class="org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint" >
        <constructor-arg value="/login" />
    </bean>
    
    <bean id="spnegoAuthenticationProcessingFilter"
        class="org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter">
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>
    
    <bean id="kerberosServiceAuthenticationProvider"
        class="org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider">
        <property name="ticketValidator">
            <bean
                class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator">
                <property name="servicePrincipal" value="${app.service-principal}" />
                <property name="keyTabLocation" value="${app.keytab-location}" />
                <property name="debug" value="true" />
            </bean>
        </property>
        <property name="userDetailsService" ref="dummyUserDetailsService" />
    </bean>
    
    <bean id="dummyUserDetailsService" class="demo.DummyUserDetailsService" />
    
    </beans>
    

    这里是我的java配置:

    @Configuration
    @EnableWebMvcSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Value("${app.service-principal}")
    private String servicePrincipal;
    
    @Value("${app.keytab-location}")
    private String keytabLocation;
    
    @Bean
    public AuthenticationManager customAuthenticationManager() throws Exception {
        return authenticationManager();
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .exceptionHandling()
                .authenticationEntryPoint(spnegoEntryPoint())
                .and()
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login").permitAll()
                .and()
            .logout()
                .permitAll()
                .and()
            .addFilterBefore(
                spnegoAuthenticationProcessingFilter(authenticationManagerBean()),
                BasicAuthenticationFilter.class);
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .authenticationProvider(kerberosAuthenticationProvider())
            .authenticationProvider(kerberosServiceAuthenticationProvider());
    }
    
    @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");
    }
    
    @Bean
    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);
        //ticketValidator.setHoldOnToGSSContext(true);
        return ticketValidator;
    }
    
    @Bean
    public DummyUserDetailsService dummyUserDetailsService() {
        return new DummyUserDetailsService();
    }
    
    }
    

    我指定对两个项目使用相同的键表,使用相同的spring引导配置在相同的环境中编译。

    使用xml配置,日志显示

    2017-08-25 12:26:37.315 DEBUG 2297 --- [nio-9000-exec-2] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider
    2017-08-25 12:26:37.315 DEBUG 2297 --- [nio-9000-exec-2] .a.KerberosServiceAuthenticationProvider : Try to validate Kerberos Token
    Found KeyTab /tmp/krb5.keytab for HTTP/mcottech2.example.com@EXAMPLE.COM
    Found KeyTab /tmp/krb5.keytab for HTTP/mcottech2.example.com@EXAMPLE.COM
    Entered Krb5Context.acceptSecContext with state=STATE_NEW
    Java config name: file:///etc/krb5.conf
    KeyTabInputStream, readName(): EXAMPLE.COM
    KeyTabInputStream, readName(): HTTP
    KeyTabInputStream, readName(): mcottech2.example.com
    KeyTab: load() entry length: 65; type: 1
    KeyTabInputStream, readName(): EXAMPLE.COM
    KeyTabInputStream, readName(): HTTP
    KeyTab: load() entry length: 61; type: 23
    Looking for keys for: HTTP/mcottech2.example.com@EXAMPLE.COM
    Added key: 23version: 45
    Added key: 18version: 45
    Added key: 17version: 45
    Found unsupported keytype (3) for HTTP/mcottech2.example.com@EXAMPLE.COM
    Found unsupported keytype (1) for HTTP/mcottech2.example.com@EXAMPLE.COM
    Added key: 17version: 44
    Added key: 23version: 44
    Added key: 18version: 44
    Added key: 17version: 44
    Found unsupported keytype (3) for HTTP/mcottech2.example.com@EXAMPLE.COM
    Found unsupported keytype (1) for HTTP/mcottech2.example.com@EXAMPLE.COM
    >>> EType: sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType
    Using builtin default etypes for permitted_enctypes
    default etypes for permitted_enctypes: 18 17 16 23.
    >>> EType: sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType
    MemoryCache: add 1503663997/005947/0A6D3E392B245A589F7F3FF28BA5991F/toto.toto@EXAMPLE.COM to toto.toto@EXAMPLE.COM|HTTP/mcottech2.example.com@EXAMPLE.COM
    >>> KrbApReq: authenticate succeed.
    Krb5Context setting peerSeqNumber to: 1289436574
    >>> EType: sun.security.krb5.internal.crypto.Aes256CtsHmacSha1EType
    Krb5Context setting mySeqNumber to: 502989002
    >>> Constrained deleg from GSSCaller{UNKNOWN}
    2017-08-25 12:26:37.364 DEBUG 2297 --- [nio-9000-exec-2] .a.KerberosServiceAuthenticationProvider : Succesfully validated toto.toto@EXAMPLE.COM
    

    2017-08-25 12:21:11.778 DEBUG 2248 --- [nio-9000-exec-4] .a.KerberosServiceAuthenticationProvider : Try to validate Kerberos Token
    Found KeyTab /tmp/file:/tmp/krb5.keytab for HTTP/mcottech2.example.com@EXAMPLE.COM
    Found KeyTab /tmp/file:/tmp/krb5.keytab for HTTP/mcottech2.example.com@EXAMPLE.COM
    Entered Krb5Context.acceptSecContext with state=STATE_NEW
    Java config name: file:///etc/krb5.conf
    Looking for keys for: HTTP/mcottech2.example.com@EXAMPLE.COM
    Looking for keys for: HTTP/mcottech2.example.com@EXAMPLE.COM
    

    有什么我忘了吗?

    1 回复  |  直到 8 年前
        1
  •  2
  •   rachelle    8 年前

    使用xml配置,在应用程序中。yml,键表位置必须是“file://”前面的绝对路径

    keytab-location: file:///tmp/krb5.keytab
    

    使用java配置,在应用程序中。yml,键表位置必须是文件协议的相对路径。

    keytab-location: krb5.keytab