【问题标题】:Ballerina Oauth2 authenticated endpoint returning a 406Ballerina Oauth2 经过身份验证的端点返回 406
【发布时间】:2020-04-23 16:09:22
【问题描述】:

我正在尝试调用使用 Oauth2 密码凭据的第 3 方服务来获取身份验证令牌。 Ballerina 正在返回以下消息。

2020-04-23 15:07:35,414 ERROR [ballerina/oauth2] - Received an invalid response with status-code: 406; and payload: {"fault":{"faultstring":"Raising fault. Fault name : RF.Raise-406-Exception","detail":{"errorcode":"steps.raisefault.RaiseFault"}}} 
2020-04-23 15:07:35,418 ERROR [ballerina/oauth2] - Failed to generate OAuth2 token. : error {ballerina/oauth2}Error message=Received an invalid response with status-code: 406; and payload: {"fault":{"faultstring":"Raising fault. Fault name : RF.Raise-406-Exception","detail":{"errorcode":"steps.raisefault.RaiseFault"}}} 
error {ballerina/http}AuthenticationFailed message=Failed to prepare request at bearer auth handler. cause=error {ballerina/auth}Error message=Failed to generate OAuth2 token. cause=error {ballerina/oauth2}Error message=Received an invalid response with status-code: 406; and payload: {"fault":{"faultstring":"Raising fault. Fault name : RF.Raise-406-Exception","detail":{"errorcode":"steps.raisefault.RaiseFault"}}}

让我感到困惑的是 406 代码,因为我已将内容类型和接受标头都设置为“应用程序/json”,这是服务所需要的。 但是,第二条消息说“无法生成 OAuth2 令牌”,那么它可能是获取返回 406 的 oauth 令牌的调用吗?如果是这样,我如何在令牌服务调用中设置接受标头?

使用 Ballerina,我调用了令牌端点并成功获得了令牌,但如果我尝试使用 PasswordGrantConfig 调用服务,则会出现这些错误。我已经尝试了我能想到的一切,并成功地使用 ClientCredentialsGrantConfig 让其他服务正常工作。 感谢您提供任何帮助。

相关代码如下。以下三个部分是 3 个不同 .bal 文件中的代码部分。

// configure the Oauth2 Config
import ballerina/config;
import ballerina/http;
import ballerina/oauth2;

public function getOauth2Handler() returns http:BearerAuthHandler {
    oauth2:PasswordGrantConfig passwordGrantConfig = {
        tokenUrl: config:getAsString("experian.authentication.tokenUrl"),
        username: config:getAsString("experian.authentication.username"),
        password: config:getAsString("experian.authentication.password"),
        clientId: config:getAsString("experian.authentication.clientId"),
        clientSecret: config:getAsString("experian.authentication.clientSecret"),
        credentialBearer: http:AUTH_HEADER_BEARER
    };
    oauth2:OutboundOAuth2Provider oauth2Provider = new (passwordGrantConfig);
    return new (oauth2Provider);
}

// Configure the API Client
http:ClientConfiguration delphiSelectClientConfig = {
    auth: {
        authHandler: experian:getOauth2Handler()
    }
};

experian:DelphiSelectClientConfig delphiSelectConfig = {
    serviceUrl: config:getAsString("experian.services.delphi-select.serviceUrl"),
    clientConfig: delphiSelectClientConfig
};

experian:DelphiSelectClient delphiSelectClient = new (delphiSelectConfig);

// Call the endpoint using the Oath2 configuration
import ballerina/http;
import ballerina/io;

public type DelphiSelectClientConfig record {
    string serviceUrl;
    http:ClientConfiguration clientConfig;
};

//==============================
//============Client============
//==============================

public type DelphiSelectClient client object {
    public http:Client clientEp;
    public http:ClientConfiguration config;

    public function __init(DelphiSelectClientConfig config) {
        http:Client httpEp = new (config.serviceUrl, {auth: config.clientConfig.auth});
        self.clientEp = httpEp;
        self.config = config.clientConfig;
    }

    public remote function newApplication() returns @untainted json|error {
        io:println("In newApplication function");
        http:Request request = new;
        json requestBody = newApplicationBody; // get test data from json in another file
        request.setJsonPayload(requestBody);

        var response = check self.clientEp->post("/application", request);
        var payload = check response.getJsonPayload();
        return payload;
    }
};

我还修改了我的测试代码以调用令牌 EP 并故意将accept 设置为不可接受的值,例如"text/csv"。在这种情况下,我得到相同的错误响应。但是将accept 设置为"*/*" 确实有效。最后一个考试; accept""(空)也失败了,所以我怀疑 BearerAuthHandler 没有为 accept 设置任何值。

那么我可以强制 BearerAuthHandler 设置 accept"application/json" 吗?

谢谢。 见下图。

此外,您引用的 Oath2 规范中的示例显示了正在设置的内容类型值。即使是 “*/*” 的值也可以,但我怀疑 Ballerina 将其留空。 我已经提出了 GitHub 问题 Need to be able to set http header values for OutboundOAuth2Provider

【问题讨论】:

  • 您调用的授权端点不接受您的请求。这就是你得到 406 的原因。你能分享你的代码没有凭据吗?
  • 请参阅How to create a Minimal, Reproducible Example。不查看导致问题的代码就无法解决问题。

标签: oauth-2.0 ballerina


【解决方案1】:

http:OutboundAuthHandler 对象的主要目标是为 http:Request 准备需要通过您调用的外部端点进行身份验证的身份验证信息。

http:BearerAuthHandler 负责添加Authorization 标头,其值为Bearer <token>。 “令牌”是使用提供的信息准备的。因此,没有选项可以强制http:BearerAuthHandler 为请求设置任何标头。

但在这种情况下,如果 API 成功响应了 Accept 标头的值为 application/json,您只需将该标头添加到 http:Request,然后再调用 POST 请求,如下所示:

request.addHeader("Accept", "application/json");

【讨论】:

  • 感谢您的帮助,但我试过了,但并没有解决问题。您的代码更改了对“业务”端点的调用的标头值。问题在于对 AuthProvider 端点的调用,该端点获取授权对“业务”端点的调用所需的授权令牌。正是 AuthProvider 端点需要特定的 Accept 标头。据我所知,无法在 oauth2:PasswordGrantConfig 或任何其他方式中设置 Accept 值。
  • @Martin 是的。无法在 Ballerina 支持的任何 OAuth2 授权类型中设置 Accept 标头。根据OAuth2 RFC,我找不到这样的行为/要求。如果我错了,请纠正我。只是为了澄清一下,您能否指出您正在调用的第 3 方令牌端点或与此相关的任何文档?
  • 参见添加的图片,显示第 3 方令牌端点对“application/json”的内容类型值的要求。
  • @Martin 感谢分享图片。根据 RFC,访问令牌请求将内容类型设置为 application/x-www-form-urlencoded,并且 Ballerina 还发送 Content-Type 标头。但在您的情况下,experian API 请求 application/json 作为 Content-Type 的值。无论如何,感谢您报告 GitHub 问题,我们将进一步讨论并更新。
  • @idclakmal 感谢您的更新。我查看了 RFC,你是对的,第 4.3.2 节确实声明 "application/x-www-form-urlencoded" 应该用于发送密码详细信息。我会联系第 3 方并让他们知道。但是,我不希望他们会改变并且我怀疑其他第 3 方的端点也不符合 RFC,所以如果 Ballerina 可以默认为 "application/x-www-form-urlencoded" 但允许开发人员为不符合要求的情况设置其他内容类型值,我认为这会很有用。亲切的问候,马丁。
猜你喜欢
  • 2019-02-10
  • 2020-08-02
  • 2022-11-01
  • 1970-01-01
  • 2014-12-18
  • 2012-04-25
  • 2021-11-04
  • 2016-11-17
  • 2012-04-19
相关资源
最近更新 更多