Пул временных портов

259
10 октября 2021, 23:30

Возникла задача по реализации OAuth fat клиента при уже существующем серверном приложении. Проблема в том, что клиент может быть подключен к серверу только после регистрации в определенной системе с указанием не только адреса подключения, но и клиентского порта.

То есть

  1. Админы регистрируют адрес клиента и порт (например, localhost:12346)
  2. Клиент запускает легковесный http сервер на localhost:12346
  3. Клиент после этого шлет запрос на сервер с параметром в запросе redirectUri=localhost:12346
  4. Сервер делает что надо, проверяет регистрации и отдает редирект на указанный localhost:12346
  5. Клиент считывает что ему надо, закрывает веб сервер и работает дальше.

Такой вот незамысловатый callback сервер для реализации OAuth в системе. Проблема тут в том, что, получается, надо хардкодить определенный порт на всех клиентах. Предустановленное ПО на клиенте - неизвестно. Гарантий, что порт при попытке запуска на клиенте, будет свободен - нет.

Потому возникает вопрос, если ли какие то пулы портов, предназначенные именно для таких временных подключений?

Пока что я склоняюсь к динамическому порту, заререзвированному в iana - то есть что то между 49152 — 65535, но как именно выбрать нужный порт пока затрудняюсь. Чтобы снизить риски, есть возможность указать до 4 портов на приложение, но надо выбрать такие порты, при которых вероятность, что они все будут одновременно заняты на любом из клиентов минимальна.

Answer 1

Использование встраиваемого браузера

Если есть возможно использовать встроенный браузер (WebKit в виде СefSharp, или хотя бы WebBrowser Control), то порт слушать необязательно. Код возвращается в виде GET-параметра, и его можно забрать напрямую из URL в момент редиректа.

В этом случае вместо localhost:port стоит указать Return URL вида urn:ietf:wg:oauth:2.0:oob или urn:ietf:wg:oauth:2.0:oob:auto - так делает, например, стандартный клиент для AzureAD, примерно так же обычно интегрируются с гуглом на декстопе.

Основной минус - встроенный бразуер или уже безнадежно устарел (WebBrowser) или весит достаточно много (WebKit).

Использование системного браузера + кастомной схемы

В реестре можно зарегистрировать кастомную схему url (mysuperscheme://), по навигацию на которую будет запущено ваше приложение. Примерно так сделан вход в Slack. Из недостатков - будет запущен новый экземпляр, и взаимодействие между ними придется организовать вручную. К тому же, некоторые бразуеры спрашивают подтверждение при запуске приложения по кастомной схеме.

Разделяемый порт 80

Стандартный System.Net.HttpListener позволяет сразу нескольким приложениям слушать на 80 порту, одновременно с IIS. Можно выбрать достаточно уникальный URL Prefix - и с большой вероятностью решить одновременно и проблему предсказуемости порта, и проблему предсказуемости настроек firewall. Из минусов - может быть занято все сразу одним сайтом на /, или каким-нибудь Skype.

Мне повезет

Попробуйте просто опросить коллег (вдруг кто-то уже реализовал такую схему) и выбросить из пула портов те, на которые завязались они. Если есть возможность - соберите статистику по открытым портам с целевых машин. Потом выберите 4 разных порта и надейтесь, что вам повезет. В качестве доп. мер, если ваше приложение зажали в угол - отбивайтесь и предлагайте закрыть приложения-конкуренты.

READ ALSO
Как лучше реализовать класс оружия?

Как лучше реализовать класс оружия?

Допустим, есть класс Player, который внутри себя хранит экземпляр интерфейса IWeapon

176
Daemon на MonoDevelop (C#)

Daemon на MonoDevelop (C#)

Мне нужно написать аналог Windows Service под Linux на MonoDevelop, который будет запускаться/завершаться из-под другой программы (как дочерний процесс)Реально...

95
Как поставить иконку в MenuItem C#?

Как поставить иконку в MenuItem C#?

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

125
Списки в c# и как их читать?

Списки в c# и как их читать?

у меня достаточно лёгий вопрос (наверное), как считать значения с списка при заданном значении? Например у меня есть список, очень большой...

165