升级到Spring secrity 5后,BCryptPasswordEncoder无法正常工作

时间:2019-06-14 15:07:42

标签: spring spring-security

升级后 -春天:4.3.23.RELEASE-> 5.1.6.RELEASE 春季安全性:4.2.12。发布-> 5.1.5。发布 我的BCryptPasswordEncoder实现不再起作用。

WARN [o.bcrypt.BCryptPasswordEncoder:90]编码后的密码看起来不像BCrypt

我添加了一些日志记录以获取rawPassword,encodedPassword

spring4: test1234,$ 2a $ 10 $ vcwRRfjPKrnXoGhDlGzJUe8ntNJEcWlHqc1l8QiDmwroB3WkJ96ma

spring5 / 5.1: 1a7emcO6sXmV,1a7emcO6sXmV

所以问题在于该方法是用一些已经编码或哈希化的密码来调用的?我在任何记录的地方都找不到这种行为。如何关闭?当然,密码以某种神奇的方式匹配,但是我没有区分大小写的行为。

public class IgnoreCaseBcryptPasswordEncoder extends BCryptPasswordEncoder {

    Logger logger = LogManager.getLogger(getClass());

    @Override
    public String encode(CharSequence rawPassword) {
        return super.encode(rawPassword.toString().trim().toLowerCase());
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        logger.trace(rawPassword + "," + encodedPassword);
        logger.trace(Arrays.toString(new Throwable().getStackTrace()));
        return super.matches(rawPassword.toString().toLowerCase(), encodedPassword);
    }
}

和XML Config:

    <bean id="passwordEncoder" class="de.k2interactive.qeep.security.oauth2.IgnoreCaseBcryptPasswordEncoder"/>

    <sec:authentication-manager id="userAuthentificationManager">
        <sec:authentication-provider user-service-ref="customUserDetailsService">
            <sec:password-encoder ref="passwordEncoder" />
        </sec:authentication-provider>
    </sec:authentication-manager>

    <oauth:authorization-server token-endpoint-url="/oauth/token" client-details-service-ref="clientDetails" token-services-ref="tokenServices">
        <oauth:authorization-code />
        <oauth:implicit />
        <oauth:refresh-token />
        <oauth:client-credentials />
        <oauth:password authentication-manager-ref="userAuthentificationManager"/>
        <oauth:custom-grant token-granter-ref="qeepFacebookLogin"/>
        <oauth:custom-grant token-granter-ref="qeepGoogleLogin"/>
        <oauth:custom-grant token-granter-ref="qeepAccountKitLogin"/>
    </oauth:authorization-server>

    <oauth:client-details-service id="clientDetails">
        <oauth:client client-id="trusted-ios-client" authorized-grant-types="password,facebook_access_token,accountkit,authorization_code,refresh_token,implicit"
                      secret="XXXcutXXX" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" /> 
        <oauth:client client-id="trusted-android-client" authorized-grant-types="password,facebook_access_token,google_access_token,accountkit,authorization_code,refresh_token,implicit"
                      secret="XXXcutXXX" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" />                      
    </oauth:client-details-service>

Stacktrace(Spring5):

[de.k2interactive.qeep.security.oauth2.IgnoreCaseBcryptPasswordEncoder.matches(IgnoreCaseBcryptPasswordEncoder.java:31), 
org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:90),
org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:166),
org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175),
org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:200),
org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:180),
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107),
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334),
org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74),
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107),
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334),
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56),
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107),
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334),
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105),
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334),
org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:157),
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334),
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215),
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178),
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357),
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270),
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193),
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166),
org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:262),
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107),
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193),
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166),
org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:109),
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193),
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166),
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200),
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96),
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490),
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139),
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92),
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:678),
org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:679),
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74),
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343),
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408),
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66),
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:836),
org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2120),
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49),
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149),
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624),
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61),
java.lang.Thread.run(Thread.java:748)]

1 个答案:

答案 0 :(得分:0)

我发现了问题所在: 如果您不使用DelegatingPasswordEncoder,则ID为passwordEncoder的passwordEncoder不仅用于匹配用户密码,而且还用于客户端密码(不需通过自动配置(beanid)明确引用)。对于以oauth编码的用户密码,一切都很好,但是客户端秘密不是以xml编码的oauth。 hack in match方法演示了这一点:

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        if (encodedPassword.startsWith("$2")) { //bcrypt encoded for the users password
            return super.matches(rawPassword.toString().toLowerCase(), encodedPassword);
        } else {
            return rawPassword.equals(encodedPassword); //plain-text (noop encoder) for the client-secret
        }
    }

所以我看到2种解决方案: 1.)oauth编码客户端秘密 2.)将DelegatingPasswordEncoder与oauth设置为默认值,并在客户端秘密中使用{noop}前缀。