是否可以在没有客户端密钥的情况下从Spring OAuth2服务器获取access_token?

时间:2017-04-11 21:35:27

标签: spring spring-security oauth spring-security-oauth2

我正在使用Spring Security的OAuth2服务器实现。我试图通过提供用户名和密码以及没有客户端密码的客户端ID,使用OAuth2“密码”授权类型从服务器的/oauth/token端点获取access_token。 只要我在HTTP请求的Authorization标头中提供客户端ID和客户端密钥,就可以正常工作:

curl -u clientid:clientsecret http://myhost ... -d "grant_type=password&username=user&password=pw&client_id=OAUTH_CLIENT"

按照此处的建议:Spring OAuth2 disable HTTP Basic Auth for TokenEndpoint,我设法禁用/auth/token端点的HTTP基本身份验证。但是当我试图通过cURL获取access_token时:

curl http://myhost ... -d "grant_type=password&username=user&password=pw&client_id=OAUTH_CLIENT"

我收到了BadCredentialsException,可以看到消息:

  

身份验证失败:密码与存储值不匹配

在我的服务器日志中。在这一点上,我有点恼火,因为我的理解是,当用户名和/或密码出错,而不是客户端ID和/或密码时,此消息才会显示。在cURL命令中另外提供客户机密码后,如下所示:

 curl http://myhost ... -d "grant_type=password&username=user&password=pw&client_id=OAUTH_CLIENT&client_secret=SECRET"

一切都很好。

这是否意味着我必须以某种方式提供客户端密钥才能访问/auth/token端点?

PS:我知道关于安全性这一事实通常是一个好主意,通过HTTP基本身份验证来保护这个端点,但是有一些用例宁愿能够做到这一点。

编辑:

我似乎找到了一种省略客户端秘密的方法。这是我的OAuth2服务器配置(请注意对allowFormAuthenticationForClients()autoApprove(true)的调用):

@Configuration
@EnableAuthorizationServer
class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    private final AuthenticationManager authenticationManager;

    public OAuth2Config(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

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

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauth) throws Exception {
        // allows access of /auth/token endpoint without HTTP Basic authentication
        oauth.allowFormAuthenticationForClients();  
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
        .inMemory()
        .withClient("acme")
        .autoApprove(true) // <- allows for client id only
        .authorizedGrantTypes("authorization_code", "refresh_token", "password").scopes("openid");
    }

}

编辑II:

此处的问题:Spring Security OAuth 2.0 - client secret always required for authorization code grant与此问题密切相关,但处理的是OAuth2授权类型“授权代码”,这会产生与授权类型“密码”相同的工作流程。< / p>

4 个答案:

答案 0 :(得分:3)

根据规范(RFC 6749),如果您的应用程序的客户端类型为 public ,则不需要客户端密钥。相反,如果客户端类型为 机密 ,则需要客户端密码。

如果Spring提供了设置客户端类型的API,请尝试将客户端类型设置为 public

答案 1 :(得分:1)

Spring Boot的实现要求传递客户端密钥以进行身份​​验证。但是,您可以通过创建类型为body, ul { margin: 0; padding: 0; } html, body, .root { height: 100%; } .root { display: flex; flex-direction: column; } main { flex: 3; background: lightyellow; } ul { display: flex; flex-direction: column; height: 100%; } ul li { flex: 1; background: aliceblue; outline: 1px solid #000; display: flex; /* align-items: center; */ justify-content: space-between; } img { /* object-fit: contain; */ } header, footer { flex: 1; } header { background: lightgray; } footer { background: lightblue; }的bean并自行配置来覆盖它。 This is the link to the documenation...

答案 2 :(得分:0)

使用基本身份验证但请将密码留空。

答案 3 :(得分:0)

AuthorizationServerConfigurerAdapter的实现中,重写configure并将密码编码器设置为原始文本编码器(请勿将其用作默认密码编码器!)。

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .passwordEncoder(plainTextPasswordEncoder())
                .allowFormAuthenticationForClients();
    }

    private PasswordEncoder plainTextPasswordEncoder() {
        return new PasswordEncoder() {
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return !StringUtils.hasText(encodedPassword) || passwordEncoder.matches(rawPassword, encodedPassword);
            }

            @Override
            public String encode(CharSequence rawPassword) {
                return passwordEncoder.encode(rawPassword);
            }
        };
    }

}

现在,对于OAuth客户端详细信息(在内存或数据库中),请将客户端密码设置为null。在这种情况下,客户端将被视为公共客户端,并且不需要client_secret参数。如果您为OAuth客户端详细信息(例如BCrypt哈希)设置了客户端机密,则该客户端将被视为机密。它将依赖默认密码编码器(例如BCrypt),并要求发送client_secret参数以获取访问令牌。