Ключи API пользователя: дублирование client_id приведет к внутренней ошибке сервера

При вызове user-api-key/new с client_id, который уже используется другим пользователем, форум выбрасывает ошибку RecordNotUnique и безмолвно завершается с внутренней ошибкой сервера.

ActiveRecord::RecordNotUnique (PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_user_api_keys_on_client_id"
DETAIL:  Key (client_id)=(893e0230d52455ea9b729334) already exists.
)
(eval):105:in `exec_params'
app/controllers/user_api_keys_controller.rb:66:in `create'

Возможно, стоит обрабатывать эту ситуацию не безмолвно, а с сообщением пользователю о том, что API-ключ с таким client ID уже существует.

Хотя это подводит меня ко второму вопросу: должны ли пользовательские API-ключи вести себя именно так? Предполагается ли, что client_id должен быть уникальным для всех пользователей?

5 лайков

Короткое напоминание для повышения видимости. Мы всё ещё довольно часто видим такие сообщения в нашем эндпоинте /logs:

image

3 лайка

Спасибо за сообщение об этой проблеме. У меня есть несколько вопросов, чтобы помочь мне разобраться в ситуации.

Можете ли вы предоставить базовый пример воспроизведения этой проблемы, чтобы я мог отладить её локально? Каков ваш сценарий использования user-api-keys? Вы используете мобильное приложение Discourse Hub или что-то другое?

1 лайк

Не уверен, какой именно пример воспроизведения вам нужен, но вот фрагмент кода на PHP, который отлично воспроизводит проблему.

Код
<?php

// openssl genrsa -out keypair.pem 2048
$keypair = openssl_pkey_get_private(file_get_contents("keypair.pem"));

// Получение открытого ключа
$public = openssl_pkey_get_details($keypair)["key"];

// Формирование запроса
$query = http_build_query([
    "auth_redirect" => "https://localhost/redirect",
    "application_name" => "Test repro",
    "client_id" => "7624a5376b7f52eb403a",
    "scopes" => "session_info",
    "nonce" => bin2hex(random_bytes(16)),
    "public_key" => $public
]);

$url = "https://forum.cfx.re/user-api-key/new?" . $query;
header("Location: " . $url);

Первая и повторяющаяся авторизация для первого пользователя проходит успешно, но при повторном использовании для другого пользователя без изменения client_id происходит ошибка.
image

Ключи API пользователей используются для того, чтобы игроки могли использовать свой аккаунт форума в игровом клиенте, чтобы они могли публиковать сообщения прямо из игры. Кроме того, у нас есть много пользователей, которые используют их для аутентификации на своих собственных веб-сайтах с помощью аккаунтов форума.

В то же время client ID должен быть уникальным для игровых клиентов, поэтому каждый клиент отображается как отдельное приложение на экране приложений. Для сценария использования на веб-сайте вам понадобится один client ID, чтобы каждое вход в систему не отображалось отдельно.

3 лайка

Интересно, удалось ли решить эту проблему

Появились ли какие-либо обновления по этому вопросу? Всё ещё неясно, должен ли client_id быть уникальным в глобальном масштабе, а не для каждого пользователя.

1 лайк

Он должен быть глобально уникальным.

Как это должно быть реализовано в случаях, когда у веб-сайта нет собственной системы аутентификации пользователей и он не должен создавать несколько пользовательских приложений API?

2 лайка

Установить cookie? Или определить его, используя хеш от чего-то, идентифицирующего пользователя (плюс что-то «секретное», чтобы внешние стороны не могли его воспроизвести)

Если приложение для аутентификации пользователей должно использоваться на нескольких компьютерах и не имеет никаких данных о пользователе до аутентификации, это невозможно.

Я не понимаю, как это связано с исходным вопросом, поскольку там описывается случай, когда один идентификатор клиента (client ID) используется несколькими пользователями, а в вашем случае, похоже, речь идёт о том, что у одного пользователя несколько идентификаторов клиентов.

Это называется идентификатором клиента (client ID), а не идентификатором пользователя (user ID), потому что у одного пользователя может быть несколько клиентов!

В большинстве стандартов, таких как OAuth, client_id описывается как «идентификатор приложения» и может использоваться для всех пользователей (не только для одного). Например, при использовании социальных логин на вашем форуме всегда используется один и тот же client_id.

Однако, поскольку API-ключи пользователей, по-видимому, разработаны в первую очередь для клиентов, таких как приложения Discourse, они могут быть уникальными. Было бы полезно узнать, являются ли они таковыми.

Ответ на этот вопрос прояснит, отсутствует ли проверка в файле user_api_keys.rb или неверен индекс в базе данных. В настоящее время такие запросы вызывают пугающую ошибку 500 и отображаются в нашем эндпоинте /logs.

1 лайк

Есть ли какие-либо новости по этому вопросу? Мы по-прежнему видим, что пользователи сталкиваются с этой проблемой.

1 лайк

Действительно, сообщение об ошибке должно быть лучше, но client_id должен быть уникальным.

Когда вы отправляете пользователей таким образом, вы должны генерировать уникальный идентификатор в вашем API-вызове. Индекс верен: один пользователь может иметь N client_id.