【问题标题】:Cannot authenticate to spring oauth authorization server with an encoded password无法使用编码密码向 Spring oauth 授权服务器进行身份验证
【发布时间】:2019-01-25 23:10:20
【问题描述】:

我正在学习如何将 oauth2 集成到我们的 Spring Boot 项目中,以保护我们的 API。因此,我从一个基本示例开始,该示例从运行良好的spring-security-oauth2-boot 读取,然后当我尝试修改密码编码器以使用我无法验证的任何编码器时。

这是我的 AuthorizationServerConfiguration:

@Component
@EnableResourceServer
@EnableAuthorizationServer
class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    AuthenticationManager authenticationManager

    AuthorizationServerConfiguration(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        this.authenticationManager = authenticationConfiguration.getAuthenticationManager()
    }

    @Override
    void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("myclient")
              //.secret("{noop}password")  <-- this works
                .secret("{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc")
                .authorizedGrantTypes("client_credentials")
                .scopes("all")
                .accessTokenValiditySeconds(3600)
    }

    @Override
    void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
    }
}

当我使用{noop}password 时,我可以成功地使用 curl 进行身份验证:

$ curl myclient:password@localhost:8080/oauth/token?scope=all -d grant_type=client_credentials
{"access_token":"4320fa79-38c2-45b1-a788-5ea1b5ce881a","token_type":"bearer","expires_in":3599,"scope":"all"}

但是当我打开任何散列时,我无法进行身份验证。我尝试过这种方式来使用 curl 进行身份验证,但没有运气:

$ curl congero:5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc@localhost:8080/oauth/token?scope=all -d grant_type=client_credentials
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
$ curl congero:{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc@localhost:8080/oauth/token?scope=all -d grant_type=client_credentials
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}

我还在代码中添加了这个 sn-p 来生成密码以进行双重检查,这给了我一个不同的散列,也用 curl 测试过,也没有运气:

PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder()
String encoded = passwordEncoder.encode('password')
println "PASSWORD: $encoded"

$ curl congero:91d1ee4784686a2e2a39c214f5a4b3ebb41e1206e2d1fc770d3ff146b034f8c156ea279c73aa1629@localhost:8080/oauth/token?scope=all -d grant_type=client_credentials
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
$ curl congero:{pbkdf2}91d1ee4784686a2e2a39c214f5a4b3ebb41e1206e2d1fc770d3ff146b034f8c156ea279c73aa1629@localhost:8080/oauth/token?scope=all -d grant_type=client_credentials
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}

我已经调试了 spring 源代码,发现在密码编码器(Pbkdf2PasswordEncoder 和 BcryptPasswordEncoder)中,密码正在使用这种方法进行解码:

private byte[] decode(String encodedBytes) {
    if(this.encodeHashAsBase64) {
        return Base64.getDecoder().decode(encodedBytes);
    }
    return Hex.decode(encodedBytes); 
}

这个Hex.decode 看起来是不匹配密码的罪魁祸首,而使用{noop} 时不会发生这种情况。

知道我在这里做错了什么吗?我错过了任何重要的步骤吗?我不清楚该文档,因为它没有显示如何逐步自定义配置。

【问题讨论】:

  • 你是怎么得到秘密{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc的?
  • @AbdelghaniRoussi 从此处的示例中复制spring.io/blog/2017/11/01/…
  • 因此您可以注册一个Pbkdf2PasswordEncoder(仅适用于 Pbkdf2 案例)或使用DelegatingPasswordEncoder,在这两种情况下您都需要一个 PasswordEncoder bean

标签: spring spring-boot groovy oauth-2.0 spring-security-oauth2


【解决方案1】:

当你开启散列时,并不意味着你需要在你的 curl 命令中传递编码后的密码,只需传递“password”,spring 就会对其进行编码并与它进行比较

"{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc"

你需要有一个 Pbkdf2PasswordEncoder 类型的 bean,所以 spring 将在散列和比较期间使用

【讨论】:

  • 我对此感到很陌生。感谢您的回答,这有助于我更好地理解。你知道/有任何文档来学习如何配置 spring-security-oauth 吗?我想学习如何一起配置spring security和oauth。顺便说一句,如果我想在基本身份验证中保护user:password,我应该使用 https,对吧?
  • @FedericoPiazza 恕我直言,我认为最好使用基于承载的身份验证,而不是每次使用用户名:密码进行身份验证
  • @AbdelghaniRoussi 我验证一次以获得访问令牌,然后我将其用作承载
  • @stacker 在我的应用程序中,管理员需要登录到用户帐户,管理员有编码密码。那么有没有办法让管理员在登录时绕过这个密码编码???请帮助我。即,在我的应用程序中,有两种方式由用户记录一种方式,通常由明文密码发生,该密码在 Spring Boot 中使用密码编码,另一种由管理员使用,其中管理员使用哈希密码,需要绕过 Spring Boot密码编码。
  • @KJEjava48 没有办法绕过这个,但你仍然可以允许管理员访问他的控制台的用户信息,这取决于你的用例
【解决方案2】:

您可以使用DelegatingPasswordEncoder

委托给另一个基于 PasswordEncoder 的密码编码器 基于前缀标识符。

密码存储格式

密码的一般格式为:{id}encodedPassword

这样,“id”是一个标识符,用于查找哪个 PasswordEncoder 应该使用“encodedPassword”是原始编码密码 对于选定的 PasswordEncoder。 “id”必须在开头 密码,以“{”开头,以“}”结尾。如果“id”不能 找到,“id”将为空。例如,以下可能是 使用不同“id”编码的密码列表。所有的原创 密码是“密码”。

{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
{noop}密码 {pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc

对于我们上面构建的 DelegatingPasswordEncoder:

  • 第一个密码的 PasswordEncoder id 为“bcrypt”,encodedPassword 为 “$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG”。什么时候 匹配它会委托给BCryptPasswordEncoder
  • 第二个将委托给NoOpPasswordEncoder
  • 第三个密码将委托给Pbkdf2PasswordEncoder

密码匹配是基于“id”和映射完成的 构造函数中提供的 PasswordEncoder 的“id”。

所以要让它工作,你应该声明一个PasswordEncoder bean(基本上你可以毫无问题地在密码编码器之间切换,你可以在每个新创建的用户上免费迁移!):

@Bean
PasswordEncoder passwordEncoder(){
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

【讨论】:

  • 感谢您的回答,我能够正确配置spring。但是,我的问题是我无法获得任何令牌,总是出现身份验证失败。使用@stacker 回答,问题是我实际上不能使用散列密码,我仍然必须在基本身份验证中使用纯文本密码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-07
  • 2018-01-14
  • 1970-01-01
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
相关资源
最近更新 更多