Конечная точка с проверкой подлинности Ballerina Oauth2 возвращает ошибку 406

Я пытаюсь вызвать стороннюю службу, которая использует учетные данные пароля Oauth2 для получения токена аутентификации. Балерина возвращает следующие сообщения.

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, который меня смущает, поскольку я установил как тип контента, так и заголовки accept на «application/json», что и требуется службе. Однако во втором сообщении говорится: «Не удалось сгенерировать токен OAuth2», поэтому может ли это быть вызов для получения токена oauth, который возвращает 406? Если да, то как мне установить заголовок accept для вызова службы токенов?

Используя Ballerina, я вызвал конечную точку токена и успешно получил токен, но если я попытаюсь вызвать службу с помощью PasswordGrantConfig, это будут ошибки, которые я получаю. Я перепробовал все, что мог придумать, и успешно заработал другие службы, использующие ClientCredentialsGrantConfig. Любая помощь принята с благодарностью.

Соответствующий код ниже. Три приведенных ниже раздела являются частями кода в трех разных файлах .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 Необходимо установить значения заголовка http для OutboundOAuth2Provider< /а>


person Martin    schedule 23.04.2020    source источник
comment
Ваш запрос неприемлем для конечной точки авторизации, к которой вы звоните. Вот почему вы получили 406. Не могли бы вы поделиться своим кодом без учетных данных?   -  person ldclakmal    schedule 23.04.2020
comment
См. Как создать минимальный воспроизводимый пример. Проблема не может быть решена без просмотра кода, который вызывает проблему.   -  person user272735    schedule 24.04.2020


Ответы (1)


Основная цель объектов http:OutboundAuthHandler состоит в том, чтобы подготовить http:Request с данными аутентификации, которые необходимо аутентифицировать с помощью внешней конечной точки, к которой вы звоните.

http:BearerAuthHandler отвечает за добавление заголовка Authorization со значением Bearer <token>. «токен» подготовлен с предоставленной информацией. Таким образом, нет возможности заставить http:BearerAuthHandler установить какой-либо заголовок для запроса.

Но в этом случае, если API успешно отвечает, если есть заголовок Accept со значением application/json, вы можете просто добавить этот заголовок в http:Request перед вызовом запроса POST следующим образом:

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

person ldclakmal    schedule 24.04.2020
comment
Спасибо за вашу помощь, но я попробовал это, и это не решает проблему. Ваш код изменяет значение заголовка для вызова конечной точки «бизнес». Проблема заключается в вызове конечной точки AuthProvider, которая получает токен авторизации, необходимый для авторизации вызова конечной точки «бизнес». Именно этой конечной точке AuthProvider требуется определенный заголовок Accept. Насколько я могу судить, невозможно установить значение Accept в oauth2:PasswordGrantConfig или каким-либо другим способом. - person Martin; 27.04.2020
comment
@ Мартин Да. Невозможно установить заголовок Accept ни в одном из типов грантов OAuth2, поддерживаемых Ballerina. Согласно RFC OAuth2, я не смог найти такое поведение/требование. Пожалуйста, поправьте меня, если я ошибаюсь. Просто чтобы уточнить, не могли бы вы указать мне конечную точку стороннего токена, к которой вы звоните, или любой документ, связанный с этим? - person ldclakmal; 27.04.2020
comment
См. добавленное изображение, показывающее требование конечной точки стороннего токена для значения типа содержимого «application/json». - person Martin; 29.04.2020
comment
@Martin Спасибо, что поделились изображением. Согласно RFC, запрос маркера доступа устанавливает тип содержимого как application/x-www-form-urlencoded, и Ballerina также отправляет заголовок Content-Type с этим. Но в вашем случае experian API запрашивает application/json в качестве значения для Content-Type. В любом случае, спасибо за сообщение о проблеме с GitHub, мы обсудим это дальше и обновим. - person ldclakmal; 29.04.2020
comment
@idclakmal Спасибо за обновление. Я просмотрел RFC, и вы правы, в разделе 4.3.2 говорится, что "application/x-www-form-urlencoded" следует использовать для отправки сведений о пароле. Я свяжусь с третьей стороной и дам им знать. Тем не менее, я не надеюсь, что они изменятся, и я подозреваю, что другие сторонние конечные точки также не соответствуют RFC, поэтому, если Ballerina может по умолчанию использовать "application/x-www-form-urlencoded", но разрешить разработчику устанавливать другие значения типа контента для несоответствующих случаев, я думаю, что это будет быть полезным. С уважением, Мартин. - person Martin; 30.04.2020
comment
@Мартин Спасибо за обновление. Мы рассмотрим ваше требование и обновим выпуск GitHub. Чтобы поддерживать подобные настраиваемые механизмы аутентификации, мы расширили наш механизм аутентификации, добавив поддержку пользовательских поставщиков аутентификации. Следовательно, для этого требования вы можете реализовать собственный поставщик исходящей аутентификации и использовать с ним уже доступный http:BearerAuthHandler. Для получения дополнительной информации см.: ballerina.io/learn/how-to-write-secure-ballerina-code/ - person ldclakmal; 01.05.2020