无法使用编码后的密码对Spring OAuth授权服务器进行身份验证

时间:2019-01-25 14:03:17

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

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

这是我的AuthorizationServerConfiguration:

body {
  font-family: Helvetica, FreeSans, sans-serif;
  background-image: url('./assets/images/background.jpg');
}

section {
  margin-top: 2em;
}

.row {
  margin-bottom: 1rem;
}

mat-form-field {
  color: @inputfield-text-color;
  width: 95%;
  margin-bottom: .5em;

  .mat-input-element {
    background-color: @inputfield-background-color;
    border-radius: .3em;
    padding: 1em 0.6em 0.2em 0.6em;
    line-height: 1.7em;
    &:disabled {
      background-color: @inputfield-disabled-color;
      color: dimgrey;
    }
  }
  .mat-form-field-label-wrapper {
    left: 0.6em;
    top: 0.3em;
    font-size: .8em;
  }
}

// here I tried to fix it, but it had no effect:    
.input-tooltip-icon {
  position: absolute;
  z-index: 1;
  top: .3em;
  right: -.50em;
  cursor: context-menu;
  color: @button-color;
}

当我使用@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) } } 时,我可以使用curl成功地进行身份验证:

{noop}password

但是,当我打开任何哈希时,我将无法进行身份验证。我尝试过这种方式来验证卷毛,但没有运气:

$ 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"}

我已经调试了spring源代码,发现在密码编码器(Pbkdf2PasswordEncoder以及BcryptPasswordEncoder)中,该密码正通过以下方法解码:

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"}

private byte[] decode(String encodedBytes) { if(this.encodeHashAsBase64) { return Base64.getDecoder().decode(encodedBytes); } return Hex.decode(encodedBytes); } 看起来是导致密码不匹配的罪魁祸首,这在使用Hex.decode时不会发生。

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

2 个答案:

答案 0 :(得分:0)

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

"{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc"

您需要具有类型Pbkdf2PasswordEncoder的bean,以便spring在散列和比较期间使用

答案 1 :(得分:0)

您可以使用DelegatingPasswordEncoder

  

一个密码编码器,它委派给另一个基于   加上前缀标识符。

     

密码存储格式

     

密码的一般格式为:{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”,编码密码为 “ $ 2a $ 10 $ dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM / BG”。什么时候 匹配它将委派给BCryptPasswordEncoder
  • 第二个将委托给NoOpPasswordEncoder
  • 第三个密码将委派给Pbkdf2PasswordEncoder
  

根据“ id”和映射完成密码匹配   “ id”代表构造函数中提供的PasswordEncoder。

因此,要使其正常工作,您应该声明一个PasswordEncoder bean(基本上,您可以毫无问题地在密码编码器之间进行切换,您可以免费获得每个新创建的用户的迁移!):

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